aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/Kconfig15
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/ac.c4
-rw-r--r--drivers/acpi/acpi_memhotplug.c11
-rw-r--r--drivers/acpi/asus_acpi.c227
-rw-r--r--drivers/acpi/battery.c4
-rw-r--r--drivers/acpi/bay.c411
-rw-r--r--drivers/acpi/bus.c78
-rw-r--r--drivers/acpi/button.c6
-rw-r--r--drivers/acpi/cm_sbs.c8
-rw-r--r--drivers/acpi/container.c4
-rw-r--r--drivers/acpi/debug.c2
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c3
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c83
-rw-r--r--drivers/acpi/dispatcher/dsobject.c62
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c2
-rw-r--r--drivers/acpi/dispatcher/dswexec.c12
-rw-r--r--drivers/acpi/dock.c388
-rw-r--r--drivers/acpi/ec.c400
-rw-r--r--drivers/acpi/executer/exconfig.c123
-rw-r--r--drivers/acpi/executer/exconvrt.c32
-rw-r--r--drivers/acpi/executer/exdump.c87
-rw-r--r--drivers/acpi/executer/exmisc.c14
-rw-r--r--drivers/acpi/executer/exoparg1.c26
-rw-r--r--drivers/acpi/executer/exoparg2.c4
-rw-r--r--drivers/acpi/executer/exresnte.c16
-rw-r--r--drivers/acpi/executer/exresolv.c60
-rw-r--r--drivers/acpi/executer/exresop.c50
-rw-r--r--drivers/acpi/executer/exstore.c61
-rw-r--r--drivers/acpi/executer/exstoren.c3
-rw-r--r--drivers/acpi/fan.c6
-rw-r--r--drivers/acpi/hardware/hwsleep.c44
-rw-r--r--drivers/acpi/namespace/Makefile2
-rw-r--r--drivers/acpi/namespace/nsdump.c5
-rw-r--r--drivers/acpi/namespace/nseval.c73
-rw-r--r--drivers/acpi/namespace/nsnames.c7
-rw-r--r--drivers/acpi/namespace/nspredef.c900
-rw-r--r--drivers/acpi/namespace/nssearch.c2
-rw-r--r--drivers/acpi/namespace/nsxfeval.c78
-rw-r--r--drivers/acpi/namespace/nsxfname.c5
-rw-r--r--drivers/acpi/numa.c2
-rw-r--r--drivers/acpi/osl.c55
-rw-r--r--drivers/acpi/parser/psloop.c2
-rw-r--r--drivers/acpi/parser/psparse.c32
-rw-r--r--drivers/acpi/pci_link.c6
-rw-r--r--drivers/acpi/pci_root.c4
-rw-r--r--drivers/acpi/pci_slot.c12
-rw-r--r--drivers/acpi/power.c74
-rw-r--r--drivers/acpi/processor_core.c6
-rw-r--r--drivers/acpi/processor_idle.c1
-rw-r--r--drivers/acpi/processor_perflib.c30
-rw-r--r--drivers/acpi/processor_throttling.c12
-rw-r--r--drivers/acpi/reboot.c25
-rw-r--r--drivers/acpi/resources/rscalc.c5
-rw-r--r--drivers/acpi/resources/rscreate.c10
-rw-r--r--drivers/acpi/sbs.c4
-rw-r--r--drivers/acpi/sbshc.c6
-rw-r--r--drivers/acpi/scan.c90
-rw-r--r--drivers/acpi/sleep/main.c66
-rw-r--r--drivers/acpi/sleep/proc.c18
-rw-r--r--drivers/acpi/system.c5
-rw-r--r--drivers/acpi/tables/tbfadt.c32
-rw-r--r--drivers/acpi/tables/tbinstal.c61
-rw-r--r--drivers/acpi/thermal.c57
-rw-r--r--drivers/acpi/toshiba_acpi.c2
-rw-r--r--drivers/acpi/utilities/utalloc.c53
-rw-r--r--drivers/acpi/utilities/utcopy.c29
-rw-r--r--drivers/acpi/utilities/utdelete.c12
-rw-r--r--drivers/acpi/utilities/utglobal.c52
-rw-r--r--drivers/acpi/utilities/utmisc.c9
-rw-r--r--drivers/acpi/utilities/utobject.c15
-rw-r--r--drivers/acpi/utilities/utxface.c7
-rw-r--r--drivers/acpi/utils.c4
-rw-r--r--drivers/acpi/video.c60
-rw-r--r--drivers/acpi/wmi.c49
-rw-r--r--drivers/ata/libata-acpi.c135
-rw-r--r--drivers/ata/libata-core.c2
-rw-r--r--drivers/ata/libata-eh.c26
-rw-r--r--drivers/ata/libata-sff.c11
-rw-r--r--drivers/ata/sata_via.c35
-rw-r--r--drivers/base/memory.c4
-rw-r--r--drivers/base/node.c69
-rw-r--r--drivers/block/DAC960.c6
-rw-r--r--drivers/block/amiflop.c46
-rw-r--r--drivers/block/aoe/aoeblk.c14
-rw-r--r--drivers/block/ataflop.c37
-rw-r--r--drivers/block/brd.c5
-rw-r--r--drivers/block/cciss.c71
-rw-r--r--drivers/block/cpqarray.c28
-rw-r--r--drivers/block/floppy.c54
-rw-r--r--drivers/block/loop.c59
-rw-r--r--drivers/block/nbd.c30
-rw-r--r--drivers/block/paride/pcd.c21
-rw-r--r--drivers/block/paride/pd.c14
-rw-r--r--drivers/block/paride/pf.c22
-rw-r--r--drivers/block/paride/pt.c2
-rw-r--r--drivers/block/pktcdvd.c56
-rw-r--r--drivers/block/swim3.c32
-rw-r--r--drivers/block/ub.c25
-rw-r--r--drivers/block/viodasd.c10
-rw-r--r--drivers/block/virtio_blk.c8
-rw-r--r--drivers/block/xd.c4
-rw-r--r--drivers/block/xd.h2
-rw-r--r--drivers/block/xen-blkfront.c15
-rw-r--r--drivers/block/xsysace.c11
-rw-r--r--drivers/block/z2ram.c7
-rw-r--r--drivers/cdrom/cdrom.c23
-rw-r--r--drivers/cdrom/gdrom.c14
-rw-r--r--drivers/cdrom/viocd.c21
-rw-r--r--drivers/char/agp/ali-agp.c2
-rw-r--r--drivers/char/agp/amd64-agp.c2
-rw-r--r--drivers/char/agp/ati-agp.c2
-rw-r--r--drivers/char/agp/backend.c2
-rw-r--r--drivers/char/agp/intel-agp.c2
-rw-r--r--drivers/char/agp/nvidia-agp.c2
-rw-r--r--drivers/char/agp/parisc-agp.c4
-rw-r--r--drivers/char/agp/via-agp.c2
-rw-r--r--drivers/char/ds1286.c34
-rw-r--r--drivers/char/ds1302.c24
-rw-r--r--drivers/char/epca.c6
-rw-r--r--drivers/char/hpet.c2
-rw-r--r--drivers/char/hvc_console.c86
-rw-r--r--drivers/char/hvc_console.h12
-rw-r--r--drivers/char/hvc_irq.c5
-rw-r--r--drivers/char/hvc_iseries.c1
-rw-r--r--drivers/char/hvc_vio.c1
-rw-r--r--drivers/char/hvc_xen.c1
-rw-r--r--drivers/char/ip27-rtc.c24
-rw-r--r--drivers/char/nvram.c6
-rw-r--r--drivers/char/pc8736x_gpio.c11
-rw-r--r--drivers/char/random.c36
-rw-r--r--drivers/char/raw.c8
-rw-r--r--drivers/char/rtc.c40
-rw-r--r--drivers/char/sx.c6
-rw-r--r--drivers/char/sysrq.c2
-rw-r--r--drivers/char/tpm/tpm.c2
-rw-r--r--drivers/char/tty_port.c2
-rw-r--r--drivers/char/virtio_console.c1
-rw-r--r--drivers/char/vr41xx_giu.c2
-rw-r--r--drivers/clocksource/acpi_pm.c7
-rw-r--r--drivers/cpuidle/cpuidle.c16
-rw-r--r--drivers/dma/Kconfig10
-rw-r--r--drivers/dma/dmatest.c7
-rw-r--r--drivers/dma/fsldma.c270
-rw-r--r--drivers/dma/fsldma.h1
-rw-r--r--drivers/dma/ioat_dma.c5
-rw-r--r--drivers/edac/cell_edac.c2
-rw-r--r--drivers/firmware/iscsi_ibft.c1
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpiolib.c6
-rw-r--r--drivers/gpio/twl4030-gpio.c521
-rw-r--r--drivers/gpu/drm/Kconfig3
-rw-r--r--drivers/gpu/drm/Makefile5
-rw-r--r--drivers/gpu/drm/drm_agpsupport.c52
-rw-r--r--drivers/gpu/drm/drm_cache.c69
-rw-r--r--drivers/gpu/drm/drm_drawable.c15
-rw-r--r--drivers/gpu/drm/drm_drv.c6
-rw-r--r--drivers/gpu/drm/drm_fops.c8
-rw-r--r--drivers/gpu/drm/drm_gem.c421
-rw-r--r--drivers/gpu/drm/drm_ioc32.c34
-rw-r--r--drivers/gpu/drm/drm_irq.c467
-rw-r--r--drivers/gpu/drm/drm_lock.c2
-rw-r--r--drivers/gpu/drm/drm_memory.c2
-rw-r--r--drivers/gpu/drm/drm_mm.c5
-rw-r--r--drivers/gpu/drm/drm_proc.c135
-rw-r--r--drivers/gpu/drm/drm_stub.c11
-rw-r--r--drivers/gpu/drm/drm_sysfs.c2
-rw-r--r--drivers/gpu/drm/i915/Makefile7
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c335
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c476
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1178
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c2570
-rw-r--r--drivers/gpu/drm/i915/i915_gem_debug.c201
-rw-r--r--drivers/gpu/drm/i915/i915_gem_proc.c301
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c257
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c583
-rw-r--r--drivers/gpu/drm/i915/i915_opregion.c371
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h1417
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c509
-rw-r--r--drivers/gpu/drm/mga/mga_drv.c29
-rw-r--r--drivers/gpu/drm/mga/mga_drv.h6
-rw-r--r--drivers/gpu/drm/mga/mga_irq.c74
-rw-r--r--drivers/gpu/drm/mga/mga_state.c2
-rw-r--r--drivers/gpu/drm/r128/r128_drv.c29
-rw-r--r--drivers/gpu/drm/r128/r128_drv.h11
-rw-r--r--drivers/gpu/drm/r128/r128_irq.c55
-rw-r--r--drivers/gpu/drm/r128/r128_state.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c53
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c32
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.h57
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq.c268
-rw-r--r--drivers/gpu/drm/radeon/radeon_state.c2
-rw-r--r--drivers/gpu/drm/sis/sis_mm.c10
-rw-r--r--drivers/gpu/drm/via/via_drv.c26
-rw-r--r--drivers/gpu/drm/via/via_drv.h16
-rw-r--r--drivers/gpu/drm/via/via_irq.c105
-rw-r--r--drivers/gpu/drm/via/via_mm.c3
-rw-r--r--drivers/hid/usbhid/hid-core.c4
-rw-r--r--drivers/hwmon/applesmc.c109
-rw-r--r--drivers/hwmon/pc87360.c248
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c21
-rw-r--r--drivers/i2c/busses/Kconfig1
-rw-r--r--drivers/i2c/busses/i2c-amd756.c5
-rw-r--r--drivers/i2c/busses/i2c-cpm.c1
-rw-r--r--drivers/i2c/busses/i2c-elektor.c3
-rw-r--r--drivers/i2c/busses/i2c-hydra.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c3
-rw-r--r--drivers/i2c/busses/i2c-viapro.c5
-rw-r--r--drivers/i2c/chips/Kconfig2
-rw-r--r--drivers/i2c/chips/Makefile3
-rw-r--r--drivers/i2c/chips/at24.c1
-rw-r--r--drivers/i2c/chips/ds1682.c1
-rw-r--r--drivers/i2c/chips/menelaus.c34
-rw-r--r--drivers/i2c/i2c-core.c3
-rw-r--r--drivers/ide/Kconfig88
-rw-r--r--drivers/ide/Makefile101
-rw-r--r--drivers/ide/aec62xx.c (renamed from drivers/ide/pci/aec62xx.c)0
-rw-r--r--drivers/ide/ali14xx.c (renamed from drivers/ide/legacy/ali14xx.c)0
-rw-r--r--drivers/ide/alim15x3.c (renamed from drivers/ide/pci/alim15x3.c)0
-rw-r--r--drivers/ide/amd74xx.c (renamed from drivers/ide/pci/amd74xx.c)0
-rw-r--r--drivers/ide/arm/Makefile10
-rw-r--r--drivers/ide/atiixp.c (renamed from drivers/ide/pci/atiixp.c)0
-rw-r--r--drivers/ide/au1xxx-ide.c (renamed from drivers/ide/mips/au1xxx-ide.c)0
-rw-r--r--drivers/ide/buddha.c (renamed from drivers/ide/legacy/buddha.c)0
-rw-r--r--drivers/ide/cmd640.c (renamed from drivers/ide/pci/cmd640.c)0
-rw-r--r--drivers/ide/cmd64x.c (renamed from drivers/ide/pci/cmd64x.c)0
-rw-r--r--drivers/ide/cs5520.c (renamed from drivers/ide/pci/cs5520.c)0
-rw-r--r--drivers/ide/cs5530.c (renamed from drivers/ide/pci/cs5530.c)0
-rw-r--r--drivers/ide/cs5535.c (renamed from drivers/ide/pci/cs5535.c)0
-rw-r--r--drivers/ide/cy82c693.c (renamed from drivers/ide/pci/cy82c693.c)0
-rw-r--r--drivers/ide/delkin_cb.c (renamed from drivers/ide/pci/delkin_cb.c)63
-rw-r--r--drivers/ide/dtc2278.c (renamed from drivers/ide/legacy/dtc2278.c)0
-rw-r--r--drivers/ide/falconide.c (renamed from drivers/ide/legacy/falconide.c)0
-rw-r--r--drivers/ide/gayle.c (renamed from drivers/ide/legacy/gayle.c)0
-rw-r--r--drivers/ide/generic.c (renamed from drivers/ide/pci/generic.c)0
-rw-r--r--drivers/ide/h8300/Makefile2
-rw-r--r--drivers/ide/hpt366.c (renamed from drivers/ide/pci/hpt366.c)35
-rw-r--r--drivers/ide/ht6560b.c (renamed from drivers/ide/legacy/ht6560b.c)0
-rw-r--r--drivers/ide/icside.c (renamed from drivers/ide/arm/icside.c)0
-rw-r--r--drivers/ide/ide-4drives.c (renamed from drivers/ide/legacy/ide-4drives.c)0
-rw-r--r--drivers/ide/ide-atapi.c2
-rw-r--r--drivers/ide/ide-cd.c83
-rw-r--r--drivers/ide/ide-cd_ioctl.c8
-rw-r--r--drivers/ide/ide-cs.c (renamed from drivers/ide/legacy/ide-cs.c)0
-rw-r--r--drivers/ide/ide-disk.c382
-rw-r--r--drivers/ide/ide-disk.h21
-rw-r--r--drivers/ide/ide-disk_ioctl.c7
-rw-r--r--drivers/ide/ide-disk_proc.c2
-rw-r--r--drivers/ide/ide-dma-sff.c2
-rw-r--r--drivers/ide/ide-floppy.c357
-rw-r--r--drivers/ide/ide-floppy.h41
-rw-r--r--drivers/ide/ide-floppy_ioctl.c36
-rw-r--r--drivers/ide/ide-floppy_proc.c2
-rw-r--r--drivers/ide/ide-gd.c396
-rw-r--r--drivers/ide/ide-gd.h44
-rw-r--r--drivers/ide/ide-h8300.c (renamed from drivers/ide/h8300/ide-h8300.c)0
-rw-r--r--drivers/ide/ide-ioctls.c3
-rw-r--r--drivers/ide/ide-iops.c2
-rw-r--r--drivers/ide/ide-probe.c1
-rw-r--r--drivers/ide/ide-proc.c6
-rw-r--r--drivers/ide/ide-tape.c33
-rw-r--r--drivers/ide/ide_arm.c (renamed from drivers/ide/arm/ide_arm.c)0
-rw-r--r--drivers/ide/ide_platform.c (renamed from drivers/ide/legacy/ide_platform.c)0
-rw-r--r--drivers/ide/it8213.c (renamed from drivers/ide/pci/it8213.c)0
-rw-r--r--drivers/ide/it821x.c (renamed from drivers/ide/pci/it821x.c)0
-rw-r--r--drivers/ide/jmicron.c (renamed from drivers/ide/pci/jmicron.c)0
-rw-r--r--drivers/ide/legacy/Makefile25
-rw-r--r--drivers/ide/macide.c (renamed from drivers/ide/legacy/macide.c)0
-rw-r--r--drivers/ide/mips/Makefile3
-rw-r--r--drivers/ide/ns87415.c (renamed from drivers/ide/pci/ns87415.c)0
-rw-r--r--drivers/ide/opti621.c (renamed from drivers/ide/pci/opti621.c)0
-rw-r--r--drivers/ide/palm_bk3710.c (renamed from drivers/ide/arm/palm_bk3710.c)0
-rw-r--r--drivers/ide/pci/Makefile44
-rw-r--r--drivers/ide/pci/hpt34x.c193
-rw-r--r--drivers/ide/pdc202xx_new.c (renamed from drivers/ide/pci/pdc202xx_new.c)0
-rw-r--r--drivers/ide/pdc202xx_old.c (renamed from drivers/ide/pci/pdc202xx_old.c)0
-rw-r--r--drivers/ide/piix.c (renamed from drivers/ide/pci/piix.c)0
-rw-r--r--drivers/ide/pmac.c (renamed from drivers/ide/ppc/pmac.c)0
-rw-r--r--drivers/ide/ppc/Makefile2
-rw-r--r--drivers/ide/q40ide.c (renamed from drivers/ide/legacy/q40ide.c)0
-rw-r--r--drivers/ide/qd65xx.c (renamed from drivers/ide/legacy/qd65xx.c)0
-rw-r--r--drivers/ide/qd65xx.h (renamed from drivers/ide/legacy/qd65xx.h)0
-rw-r--r--drivers/ide/rapide.c (renamed from drivers/ide/arm/rapide.c)0
-rw-r--r--drivers/ide/rz1000.c (renamed from drivers/ide/pci/rz1000.c)0
-rw-r--r--drivers/ide/sc1200.c (renamed from drivers/ide/pci/sc1200.c)0
-rw-r--r--drivers/ide/scc_pata.c (renamed from drivers/ide/pci/scc_pata.c)4
-rw-r--r--drivers/ide/serverworks.c (renamed from drivers/ide/pci/serverworks.c)0
-rw-r--r--drivers/ide/sgiioc4.c (renamed from drivers/ide/pci/sgiioc4.c)49
-rw-r--r--drivers/ide/siimage.c (renamed from drivers/ide/pci/siimage.c)0
-rw-r--r--drivers/ide/sis5513.c (renamed from drivers/ide/pci/sis5513.c)0
-rw-r--r--drivers/ide/sl82c105.c (renamed from drivers/ide/pci/sl82c105.c)0
-rw-r--r--drivers/ide/slc90e66.c (renamed from drivers/ide/pci/slc90e66.c)0
-rw-r--r--drivers/ide/tc86c001.c (renamed from drivers/ide/pci/tc86c001.c)0
-rw-r--r--drivers/ide/triflex.c (renamed from drivers/ide/pci/triflex.c)0
-rw-r--r--drivers/ide/trm290.c (renamed from drivers/ide/pci/trm290.c)0
-rw-r--r--drivers/ide/umc8672.c (renamed from drivers/ide/legacy/umc8672.c)0
-rw-r--r--drivers/ide/via82cxxx.c (renamed from drivers/ide/pci/via82cxxx.c)0
-rw-r--r--drivers/idle/Kconfig16
-rw-r--r--drivers/idle/Makefile2
-rw-r--r--drivers/idle/i7300_idle.c674
-rw-r--r--drivers/infiniband/core/cm.c2
-rw-r--r--drivers/infiniband/core/mad.c14
-rw-r--r--drivers/infiniband/core/ucma.c4
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c1
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c83
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c10
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c6
-rw-r--r--drivers/infiniband/hw/mlx4/main.c11
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h1
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c21
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ethtool.c9
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c7
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c67
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c4
-rw-r--r--drivers/input/joystick/iforce/iforce-ff.c36
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c14
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c8
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c2
-rw-r--r--drivers/input/joystick/xpad.c2
-rw-r--r--drivers/input/misc/ati_remote.c20
-rw-r--r--drivers/input/misc/yealink.c3
-rw-r--r--drivers/input/tablet/acecad.c3
-rw-r--r--drivers/input/tablet/aiptek.c26
-rw-r--r--drivers/input/tablet/gtco.c4
-rw-r--r--drivers/input/tablet/kbtab.c3
-rw-r--r--drivers/input/tablet/wacom_sys.c3
-rw-r--r--drivers/input/touchscreen/Kconfig2
-rw-r--r--drivers/input/touchscreen/hp680_ts_input.c2
-rw-r--r--drivers/leds/Kconfig2
-rw-r--r--drivers/leds/leds-hp6xx.c2
-rw-r--r--drivers/md/Makefile2
-rw-r--r--drivers/md/dm-crypt.c56
-rw-r--r--drivers/md/dm-delay.c3
-rw-r--r--drivers/md/dm-exception-store.c108
-rw-r--r--drivers/md/dm-io.c2
-rw-r--r--drivers/md/dm-ioctl.c4
-rw-r--r--drivers/md/dm-kcopyd.c14
-rw-r--r--drivers/md/dm-linear.c15
-rw-r--r--drivers/md/dm-log.c2
-rw-r--r--drivers/md/dm-mpath.c17
-rw-r--r--drivers/md/dm-path-selector.c3
-rw-r--r--drivers/md/dm-raid1.c791
-rw-r--r--drivers/md/dm-region-hash.c704
-rw-r--r--drivers/md/dm-round-robin.c3
-rw-r--r--drivers/md/dm-snap.c11
-rw-r--r--drivers/md/dm-snap.h5
-rw-r--r--drivers/md/dm-stripe.c6
-rw-r--r--drivers/md/dm-table.c37
-rw-r--r--drivers/md/dm-zero.c2
-rw-r--r--drivers/md/dm.c76
-rw-r--r--drivers/md/dm.h9
-rw-r--r--drivers/md/md.c20
-rw-r--r--drivers/media/common/saa7146_fops.c4
-rw-r--r--drivers/media/common/saa7146_video.c12
-rw-r--r--drivers/media/common/tuners/mxl5005s.c10
-rw-r--r--drivers/media/common/tuners/tuner-simple.c2
-rw-r--r--drivers/media/common/tuners/tuner-types.c33
-rw-r--r--drivers/media/common/tuners/xc5000.c73
-rw-r--r--drivers/media/common/tuners/xc5000.h8
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c12
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c134
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h1
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h4
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c12
-rw-r--r--drivers/media/dvb/frontends/cx22702.c506
-rw-r--r--drivers/media/dvb/frontends/cx22702.h20
-rw-r--r--drivers/media/dvb/frontends/cx24116.c589
-rw-r--r--drivers/media/dvb/frontends/cx24116.h21
-rw-r--r--drivers/media/dvb/frontends/cx24123.c228
-rw-r--r--drivers/media/dvb/frontends/cx24123.h10
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c138
-rw-r--r--drivers/media/dvb/frontends/s5h1409.h15
-rw-r--r--drivers/media/dvb/frontends/s5h1411.c92
-rw-r--r--drivers/media/dvb/frontends/s5h1411.h2
-rw-r--r--drivers/media/dvb/frontends/tda10048.c100
-rw-r--r--drivers/media/dvb/frontends/z0194a.h16
-rw-r--r--drivers/media/dvb/siano/sms-cards.c4
-rw-r--r--drivers/media/dvb/ttpci/av7110.c2
-rw-r--r--drivers/media/radio/Kconfig2
-rw-r--r--drivers/media/radio/dsbr100.c75
-rw-r--r--drivers/media/radio/radio-mr800.c5
-rw-r--r--drivers/media/radio/radio-si470x.c234
-rw-r--r--drivers/media/video/adv7170.c251
-rw-r--r--drivers/media/video/adv7175.c243
-rw-r--r--drivers/media/video/arv.c2
-rw-r--r--drivers/media/video/au0828/au0828-cards.c5
-rw-r--r--drivers/media/video/au0828/au0828-core.c3
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c3
-rw-r--r--drivers/media/video/bt819.c321
-rw-r--r--drivers/media/video/bt856.c218
-rw-r--r--drivers/media/video/bt866.c255
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c6
-rw-r--r--drivers/media/video/c-qcam.c2
-rw-r--r--drivers/media/video/cafe_ccic.c4
-rw-r--r--drivers/media/video/cpia.c6
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c11
-rw-r--r--drivers/media/video/cx18/cx18-driver.h1
-rw-r--r--drivers/media/video/cx18/cx18-io.h4
-rw-r--r--drivers/media/video/cx18/cx18-streams.c36
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c152
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c276
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c190
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c47
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c27
-rw-r--r--drivers/media/video/cx23885/cx23885.h26
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c2
-rw-r--r--drivers/media/video/cx88/cx88-cards.c58
-rw-r--r--drivers/media/video/cx88/cx88-core.c3
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c410
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c19
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c21
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c11
-rw-r--r--drivers/media/video/cx88/cx88-video.c58
-rw-r--r--drivers/media/video/cx88/cx88.h7
-rw-r--r--drivers/media/video/dabusb.c4
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c2
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c24
-rw-r--r--drivers/media/video/gspca/gspca.c3
-rw-r--r--drivers/media/video/gspca/gspca.h1
-rw-r--r--drivers/media/video/gspca/m5602/m5602_bridge.h29
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c46
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.c18
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.h7
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.c40
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.h3
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.c90
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.h46
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.c22
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.h3
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c6
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.h4
-rw-r--r--drivers/media/video/gspca/m5602/m5602_sensor.h2
-rw-r--r--drivers/media/video/gspca/t613.c375
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c12
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c15
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c1
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c31
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.h3
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c4
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c6
-rw-r--r--drivers/media/video/ks0127.c476
-rw-r--r--drivers/media/video/ov511.c19
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c17
-rw-r--r--drivers/media/video/pwc/pwc-if.c2
-rw-r--r--drivers/media/video/saa7110.c242
-rw-r--r--drivers/media/video/saa7111.c224
-rw-r--r--drivers/media/video/saa7114.c364
-rw-r--r--drivers/media/video/saa7127.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c216
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c2
-rw-r--r--drivers/media/video/saa7134/saa7134.h2
-rw-r--r--drivers/media/video/saa7185.c210
-rw-r--r--drivers/media/video/se401.c2
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c96
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c24
-rw-r--r--drivers/media/video/soc_camera_platform.c20
-rw-r--r--drivers/media/video/stk-webcam.c31
-rw-r--r--drivers/media/video/stk-webcam.h1
-rw-r--r--drivers/media/video/stv680.c3
-rw-r--r--drivers/media/video/tveeprom.c2
-rw-r--r--drivers/media/video/usbvideo/konicawc.c8
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c14
-rw-r--r--drivers/media/video/usbvideo/usbvideo.c2
-rw-r--r--drivers/media/video/usbvideo/vicam.c3
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c2
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c12
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c12
-rw-r--r--drivers/media/video/v4l1-compat.c221
-rw-r--r--drivers/media/video/v4l2-int-device.c5
-rw-r--r--drivers/media/video/v4l2-ioctl.c19
-rw-r--r--drivers/media/video/videobuf-dvb.c207
-rw-r--r--drivers/media/video/vivi.c284
-rw-r--r--drivers/media/video/vpx3220.c328
-rw-r--r--drivers/media/video/w9968cf.c16
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c24
-rw-r--r--drivers/media/video/zoran/zoran_card.c1
-rw-r--r--drivers/media/video/zoran/zoran_driver.c1
-rw-r--r--drivers/media/video/zr364xx.c2
-rw-r--r--drivers/memstick/core/mspro_block.c10
-rw-r--r--drivers/message/i2o/i2o_block.c13
-rw-r--r--drivers/mfd/Kconfig16
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/asic3.c4
-rw-r--r--drivers/mfd/da903x.c563
-rw-r--r--drivers/mfd/htc-egpio.c4
-rw-r--r--drivers/mfd/mfd-core.c15
-rw-r--r--drivers/mfd/sm501.c31
-rw-r--r--drivers/mfd/t7l66xb.c40
-rw-r--r--drivers/mfd/tc6387xb.c47
-rw-r--r--drivers/mfd/tc6393xb.c296
-rw-r--r--drivers/mfd/twl4030-core.c806
-rw-r--r--drivers/mfd/twl4030-irq.c743
-rw-r--r--drivers/mfd/wm8350-core.c7
-rw-r--r--drivers/misc/Kconfig12
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/acer-wmi.c225
-rw-r--r--drivers/misc/asus-laptop.c17
-rw-r--r--drivers/misc/eeepc-laptop.c232
-rw-r--r--drivers/misc/fujitsu-laptop.c135
-rw-r--r--drivers/misc/hp-wmi.c1
-rw-r--r--drivers/misc/intel_menlow.c31
-rw-r--r--drivers/misc/panasonic-laptop.c767
-rw-r--r--drivers/misc/sony-laptop.c2
-rw-r--r--drivers/misc/thinkpad_acpi.c65
-rw-r--r--drivers/mmc/card/block.c13
-rw-r--r--drivers/mmc/card/queue.c1
-rw-r--r--drivers/mmc/host/s3cmci.c210
-rw-r--r--drivers/mmc/host/s3cmci.h6
-rw-r--r--drivers/mtd/Kconfig5
-rw-r--r--drivers/mtd/chips/Kconfig4
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c71
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c52
-rw-r--r--drivers/mtd/chips/cfi_probe.c58
-rw-r--r--drivers/mtd/chips/cfi_util.c66
-rw-r--r--drivers/mtd/chips/gen_probe.c2
-rw-r--r--drivers/mtd/cmdlinepart.c1
-rw-r--r--drivers/mtd/devices/Kconfig21
-rw-r--r--drivers/mtd/devices/block2mtd.c4
-rw-r--r--drivers/mtd/devices/m25p80.c138
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c214
-rw-r--r--drivers/mtd/inftlcore.c5
-rw-r--r--drivers/mtd/maps/Kconfig33
-rw-r--r--drivers/mtd/maps/Makefile4
-rw-r--r--drivers/mtd/maps/ebony.c163
-rw-r--r--drivers/mtd/maps/ocotea.c154
-rw-r--r--drivers/mtd/maps/omap-toto-flash.c133
-rw-r--r--drivers/mtd/maps/pci.c18
-rw-r--r--drivers/mtd/maps/physmap_of.c3
-rw-r--r--drivers/mtd/maps/walnut.c122
-rw-r--r--drivers/mtd/mtd_blkdevs.c24
-rw-r--r--drivers/mtd/mtdchar.c14
-rw-r--r--drivers/mtd/mtdconcat.c4
-rw-r--r--drivers/mtd/mtdoops.c42
-rw-r--r--drivers/mtd/mtdpart.c4
-rw-r--r--drivers/mtd/nand/Kconfig42
-rw-r--r--drivers/mtd/nand/Makefile4
-rw-r--r--drivers/mtd/nand/alauda.c4
-rw-r--r--drivers/mtd/nand/atmel_nand.c58
-rw-r--r--drivers/mtd/nand/cs553x_nand.c2
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c3
-rw-r--r--drivers/mtd/nand/fsl_upm.c68
-rw-r--r--drivers/mtd/nand/gpio.c375
-rw-r--r--drivers/mtd/nand/mxc_nand.c1077
-rw-r--r--drivers/mtd/nand/nand_base.c16
-rw-r--r--drivers/mtd/nand/nand_ecc.c554
-rw-r--r--drivers/mtd/nand/nandsim.c1
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c147
-rw-r--r--drivers/mtd/nand/sh_flctl.c878
-rw-r--r--drivers/mtd/nand/toto.c206
-rw-r--r--drivers/mtd/ofpart.c1
-rw-r--r--drivers/mtd/onenand/Kconfig8
-rw-r--r--drivers/mtd/onenand/Makefile1
-rw-r--r--drivers/mtd/onenand/omap2.c802
-rw-r--r--drivers/mtd/onenand/onenand_base.c2
-rw-r--r--drivers/mtd/ssfdc.c3
-rw-r--r--drivers/mtd/ubi/cdev.c6
-rw-r--r--drivers/mtd/ubi/scan.c2
-rw-r--r--drivers/mtd/ubi/vtbl.c4
-rw-r--r--drivers/net/3c59x.c4
-rw-r--r--drivers/net/Kconfig15
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/fec_mpc52xx_phy.c55
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c4
-rw-r--r--drivers/net/hamradio/scc.c6
-rw-r--r--drivers/net/ibm_newemac/core.c10
-rw-r--r--drivers/net/ibm_newemac/mal.c15
-rw-r--r--drivers/net/irda/kingsun-sir.c3
-rw-r--r--drivers/net/irda/ks959-sir.c3
-rw-r--r--drivers/net/irda/ksdazzle-sir.c3
-rw-r--r--drivers/net/irda/stir4200.c18
-rw-r--r--drivers/net/mlx4/Makefile7
-rw-r--r--drivers/net/mlx4/alloc.c97
-rw-r--r--drivers/net/mlx4/cq.c2
-rw-r--r--drivers/net/mlx4/en_cq.c146
-rw-r--r--drivers/net/mlx4/en_main.c254
-rw-r--r--drivers/net/mlx4/en_netdev.c1088
-rw-r--r--drivers/net/mlx4/en_params.c480
-rw-r--r--drivers/net/mlx4/en_port.c261
-rw-r--r--drivers/net/mlx4/en_port.h570
-rw-r--r--drivers/net/mlx4/en_resources.c96
-rw-r--r--drivers/net/mlx4/en_rx.c1080
-rw-r--r--drivers/net/mlx4/en_tx.c820
-rw-r--r--drivers/net/mlx4/eq.c2
-rw-r--r--drivers/net/mlx4/fw.c20
-rw-r--r--drivers/net/mlx4/fw.h7
-rw-r--r--drivers/net/mlx4/main.c287
-rw-r--r--drivers/net/mlx4/mcg.c4
-rw-r--r--drivers/net/mlx4/mlx4.h45
-rw-r--r--drivers/net/mlx4/mlx4_en.h561
-rw-r--r--drivers/net/mlx4/mr.c2
-rw-r--r--drivers/net/mlx4/pd.c4
-rw-r--r--drivers/net/mlx4/port.c282
-rw-r--r--drivers/net/mlx4/qp.c81
-rw-r--r--drivers/net/mlx4/srq.c2
-rw-r--r--drivers/net/sh_eth.c5
-rw-r--r--drivers/net/usb/catc.c8
-rw-r--r--drivers/net/usb/kaweth.c27
-rw-r--r--drivers/net/usb/pegasus.c4
-rw-r--r--drivers/net/usb/rtl8150.c31
-rw-r--r--drivers/net/wan/sbni.c2
-rw-r--r--drivers/net/xtsonic.c319
-rw-r--r--drivers/of/of_i2c.c2
-rw-r--r--drivers/of/of_spi.c2
-rw-r--r--drivers/oprofile/buffer_sync.c41
-rw-r--r--drivers/oprofile/buffer_sync.h4
-rw-r--r--drivers/oprofile/cpu_buffer.c106
-rw-r--r--drivers/oprofile/cpu_buffer.h12
-rw-r--r--drivers/oprofile/event_buffer.c34
-rw-r--r--drivers/oprofile/event_buffer.h17
-rw-r--r--drivers/oprofile/oprof.c26
-rw-r--r--drivers/oprofile/oprof.h12
-rw-r--r--drivers/oprofile/oprofile_files.c36
-rw-r--r--drivers/oprofile/oprofile_stats.c24
-rw-r--r--drivers/oprofile/oprofile_stats.h10
-rw-r--r--drivers/oprofile/oprofilefs.c78
-rw-r--r--drivers/oprofile/timer_int.c4
-rw-r--r--drivers/parisc/ccio-dma.c43
-rw-r--r--drivers/parisc/dino.c6
-rw-r--r--drivers/parisc/eisa.c4
-rw-r--r--drivers/parisc/eisa_eeprom.c2
-rw-r--r--drivers/parisc/gsc.c12
-rw-r--r--drivers/parisc/iosapic.c4
-rw-r--r--drivers/parisc/superio.c4
-rw-r--r--drivers/parport/parport_pc.c20
-rw-r--r--drivers/pci/bus.c7
-rw-r--r--drivers/pci/dmar.c176
-rw-r--r--drivers/pci/hotplug/acpiphp.h9
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c32
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c20
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c2
-rw-r--r--drivers/pci/hotplug/cpci_hotplug.h6
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c75
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c4
-rw-r--r--drivers/pci/hotplug/cpqphp.h13
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c43
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c2
-rw-r--r--drivers/pci/hotplug/fakephp.c26
-rw-r--r--drivers/pci/hotplug/ibmphp.h5
-rw-r--r--drivers/pci/hotplug/ibmphp_ebda.c111
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c78
-rw-r--r--drivers/pci/hotplug/pciehp.h26
-rw-r--r--drivers/pci/hotplug/pciehp_core.c103
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c144
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c262
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c26
-rw-r--r--drivers/pci/hotplug/rpaphp.h4
-rw-r--r--drivers/pci/hotplug/rpaphp_core.c4
-rw-r--r--drivers/pci/hotplug/rpaphp_pci.c2
-rw-r--r--drivers/pci/hotplug/rpaphp_slot.c10
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c22
-rw-r--r--drivers/pci/hotplug/shpchp.h9
-rw-r--r--drivers/pci/hotplug/shpchp_core.c52
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c48
-rw-r--r--drivers/pci/htirq.c3
-rw-r--r--drivers/pci/intel-iommu.c254
-rw-r--r--drivers/pci/intr_remapping.c139
-rw-r--r--drivers/pci/msi.c31
-rw-r--r--drivers/pci/pci-acpi.c85
-rw-r--r--drivers/pci/pci-driver.c21
-rw-r--r--drivers/pci/pci-sysfs.c241
-rw-r--r--drivers/pci/pci.c197
-rw-r--r--drivers/pci/pci.h28
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c6
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c47
-rw-r--r--drivers/pci/pcie/aspm.c6
-rw-r--r--drivers/pci/pcie/portdrv.h1
-rw-r--r--drivers/pci/pcie/portdrv_core.c23
-rw-r--r--drivers/pci/pcie/portdrv_pci.c2
-rw-r--r--drivers/pci/probe.c147
-rw-r--r--drivers/pci/quirks.c187
-rw-r--r--drivers/pci/remove.c11
-rw-r--r--drivers/pci/rom.c6
-rw-r--r--drivers/pci/search.c9
-rw-r--r--drivers/pci/setup-bus.c17
-rw-r--r--drivers/pci/setup-res.c42
-rw-r--r--drivers/pci/slot.c170
-rw-r--r--drivers/pcmcia/Makefile2
-rw-r--r--drivers/pcmcia/at91_cf.c2
-rw-r--r--drivers/pcmcia/hd64465_ss.c12
-rw-r--r--drivers/pcmcia/vrc4171_card.c2
-rw-r--r--drivers/pnp/Kconfig20
-rw-r--r--drivers/pnp/Makefile4
-rw-r--r--drivers/pnp/base.h10
-rw-r--r--drivers/pnp/core.c29
-rw-r--r--drivers/pnp/driver.c4
-rw-r--r--drivers/pnp/isapnp/Makefile4
-rw-r--r--drivers/pnp/isapnp/core.c12
-rw-r--r--drivers/pnp/manager.c34
-rw-r--r--drivers/pnp/pnpacpi/Makefile4
-rw-r--r--drivers/pnp/pnpacpi/core.c16
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c43
-rw-r--r--drivers/pnp/pnpbios/Makefile4
-rw-r--r--drivers/pnp/pnpbios/core.c4
-rw-r--r--drivers/pnp/pnpbios/rsparser.c18
-rw-r--r--drivers/pnp/quirks.c5
-rw-r--r--drivers/pnp/resource.c12
-rw-r--r--drivers/pnp/support.c14
-rw-r--r--drivers/power/Kconfig8
-rw-r--r--drivers/power/Makefile3
-rw-r--r--drivers/power/bq27x00_battery.c381
-rw-r--r--drivers/power/pda_power.c11
-rw-r--r--drivers/power/power_supply_core.c25
-rw-r--r--drivers/power/power_supply_sysfs.c2
-rw-r--r--drivers/ps3/ps3av.c16
-rw-r--r--drivers/ps3/ps3av_cmd.c19
-rw-r--r--drivers/rtc/Kconfig22
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/rtc-at91rm9200.c42
-rw-r--r--drivers/rtc/rtc-bq4802.c30
-rw-r--r--drivers/rtc/rtc-cmos.c91
-rw-r--r--drivers/rtc/rtc-ds1216.c26
-rw-r--r--drivers/rtc/rtc-ds1302.c30
-rw-r--r--drivers/rtc/rtc-ds1305.c39
-rw-r--r--drivers/rtc/rtc-ds1307.c41
-rw-r--r--drivers/rtc/rtc-ds1511.c43
-rw-r--r--drivers/rtc/rtc-ds1553.c38
-rw-r--r--drivers/rtc/rtc-ds1742.c30
-rw-r--r--drivers/rtc/rtc-fm3130.c56
-rw-r--r--drivers/rtc/rtc-isl1208.c42
-rw-r--r--drivers/rtc/rtc-m41t80.c44
-rw-r--r--drivers/rtc/rtc-m41t94.c28
-rw-r--r--drivers/rtc/rtc-m48t59.c49
-rw-r--r--drivers/rtc/rtc-m48t86.c28
-rw-r--r--drivers/rtc/rtc-max6900.c32
-rw-r--r--drivers/rtc/rtc-max6902.c32
-rw-r--r--drivers/rtc/rtc-omap.c24
-rw-r--r--drivers/rtc/rtc-parisc.c111
-rw-r--r--drivers/rtc/rtc-pcf8563.c24
-rw-r--r--drivers/rtc/rtc-pcf8583.c20
-rw-r--r--drivers/rtc/rtc-r9701.c24
-rw-r--r--drivers/rtc/rtc-rs5c313.c28
-rw-r--r--drivers/rtc/rtc-rs5c348.c30
-rw-r--r--drivers/rtc/rtc-rs5c372.c42
-rw-r--r--drivers/rtc/rtc-s35390a.c34
-rw-r--r--drivers/rtc/rtc-s3c.c42
-rw-r--r--drivers/rtc/rtc-sh.c61
-rw-r--r--drivers/rtc/rtc-stk17ta8.c39
-rw-r--r--drivers/rtc/rtc-twl4030.c564
-rw-r--r--drivers/rtc/rtc-v3020.c28
-rw-r--r--drivers/rtc/rtc-vr41xx.c4
-rw-r--r--drivers/rtc/rtc-x1205.c30
-rw-r--r--drivers/s390/block/dasd.c11
-rw-r--r--drivers/s390/block/dasd_genhd.c4
-rw-r--r--drivers/s390/block/dasd_int.h3
-rw-r--r--drivers/s390/block/dasd_ioctl.c15
-rw-r--r--drivers/s390/block/dcssblk.c17
-rw-r--r--drivers/s390/char/tape_block.c25
-rw-r--r--drivers/s390/crypto/ap_bus.c6
-rw-r--r--drivers/scsi/aha152x.c2
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c3
-rw-r--r--drivers/scsi/ide-scsi.c48
-rw-r--r--drivers/scsi/ipr.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c5
-rw-r--r--drivers/scsi/scsi_ioctl.c6
-rw-r--r--drivers/scsi/sd.c35
-rw-r--r--drivers/scsi/sg.c2
-rw-r--r--drivers/scsi/sr.c40
-rw-r--r--drivers/scsi/sr_vendor.c12
-rw-r--r--drivers/scsi/st.c7
-rw-r--r--drivers/serial/68328serial.c11
-rw-r--r--drivers/serial/8250.c69
-rw-r--r--drivers/serial/8250_gsc.c2
-rw-r--r--drivers/serial/8250_pci.c231
-rw-r--r--drivers/serial/Kconfig2
-rw-r--r--drivers/serial/amba-pl010.c2
-rw-r--r--drivers/serial/amba-pl011.c2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/serial/m32r_sio.c4
-rw-r--r--drivers/serial/serial_core.c2
-rw-r--r--drivers/serial/serial_lh7a40x.c2
-rw-r--r--drivers/serial/serial_txx9.c2
-rw-r--r--drivers/serial/sh-sci.c92
-rw-r--r--drivers/serial/sh-sci.h23
-rw-r--r--drivers/serial/sn_console.c2
-rw-r--r--drivers/serial/ucc_uart.c2
-rw-r--r--drivers/sh/Makefile2
-rw-r--r--drivers/sh/intc.c713
-rw-r--r--drivers/staging/Kconfig4
-rw-r--r--drivers/staging/Makefile2
-rw-r--r--drivers/staging/at76_usb/at76_usb.c4
-rw-r--r--drivers/staging/echo/bit_operations.h205
-rw-r--r--drivers/staging/echo/echo.c835
-rw-r--r--drivers/staging/echo/echo.h58
-rw-r--r--drivers/staging/echo/fir.h376
-rw-r--r--drivers/staging/echo/mmx.h29
-rw-r--r--drivers/staging/echo/oslec.h86
-rw-r--r--drivers/staging/et131x/et1310_phy.c2
-rw-r--r--drivers/staging/et131x/et131x_debug.c1
-rw-r--r--drivers/staging/et131x/et131x_initpci.c1
-rw-r--r--drivers/staging/go7007/Kconfig2
-rw-r--r--drivers/staging/go7007/go7007-driver.c1
-rw-r--r--drivers/staging/go7007/go7007-fw.c1
-rw-r--r--drivers/staging/go7007/go7007-i2c.c1
-rw-r--r--drivers/staging/go7007/go7007-usb.c1
-rw-r--r--drivers/staging/go7007/snd-go7007.c1
-rw-r--r--drivers/staging/go7007/wis-ov7640.c1
-rw-r--r--drivers/staging/go7007/wis-saa7113.c1
-rw-r--r--drivers/staging/go7007/wis-saa7115.c1
-rw-r--r--drivers/staging/go7007/wis-sony-tuner.c1
-rw-r--r--drivers/staging/go7007/wis-tw2804.c1
-rw-r--r--drivers/staging/go7007/wis-tw9903.c1
-rw-r--r--drivers/staging/go7007/wis-uda1342.c1
-rw-r--r--drivers/staging/me4000/me4000.c908
-rw-r--r--drivers/staging/me4000/me4000.h194
-rw-r--r--drivers/staging/pcc-acpi/Kconfig11
-rw-r--r--drivers/staging/pcc-acpi/Makefile1
-rw-r--r--drivers/staging/pcc-acpi/TODO7
-rw-r--r--drivers/staging/pcc-acpi/pcc-acpi.c1111
-rw-r--r--drivers/staging/poch/Kconfig6
-rw-r--r--drivers/staging/poch/Makefile1
-rw-r--r--drivers/staging/poch/README7
-rw-r--r--drivers/staging/poch/poch.c1425
-rw-r--r--drivers/staging/poch/poch.h29
-rw-r--r--drivers/staging/slicoss/slicoss.c18
-rw-r--r--drivers/staging/sxg/Kconfig1
-rw-r--r--drivers/staging/sxg/README1
-rw-r--r--drivers/staging/sxg/sxg.c1379
-rw-r--r--drivers/staging/sxg/sxg_os.h41
-rw-r--r--drivers/staging/sxg/sxgdbg.h2
-rw-r--r--drivers/staging/sxg/sxghif.h410
-rw-r--r--drivers/staging/sxg/sxghw.h404
-rw-r--r--drivers/staging/sxg/sxgphycode.h12
-rw-r--r--drivers/staging/usbip/usbip_common.c2
-rw-r--r--drivers/staging/usbip/vhci_rx.c2
-rw-r--r--drivers/staging/winbond/Kconfig2
-rw-r--r--drivers/staging/winbond/README1
-rw-r--r--drivers/staging/winbond/bss_f.h6
-rw-r--r--drivers/staging/winbond/ds_tkip.h6
-rw-r--r--drivers/staging/winbond/linux/common.h17
-rw-r--r--drivers/staging/winbond/linux/wb35reg.c63
-rw-r--r--drivers/staging/winbond/linux/wb35reg_f.h12
-rw-r--r--drivers/staging/winbond/linux/wb35reg_s.h4
-rw-r--r--drivers/staging/winbond/linux/wb35rx.c175
-rw-r--r--drivers/staging/winbond/linux/wb35rx_s.h2
-rw-r--r--drivers/staging/winbond/linux/wb35tx.c138
-rw-r--r--drivers/staging/winbond/linux/wb35tx_f.h2
-rw-r--r--drivers/staging/winbond/linux/wbusb.c259
-rw-r--r--drivers/staging/winbond/mds.c30
-rw-r--r--drivers/staging/winbond/mds_f.h6
-rw-r--r--drivers/staging/winbond/mds_s.h8
-rw-r--r--drivers/staging/winbond/mlme_s.h4
-rw-r--r--drivers/staging/winbond/mlmetxrx.c4
-rw-r--r--drivers/staging/winbond/mlmetxrx_f.h4
-rw-r--r--drivers/staging/winbond/reg.c24
-rw-r--r--drivers/staging/winbond/sme_api.c1
-rw-r--r--drivers/staging/winbond/sme_api.h2
-rw-r--r--drivers/staging/winbond/wbhal.c32
-rw-r--r--drivers/staging/winbond/wbhal_f.h28
-rw-r--r--drivers/staging/winbond/wbhal_s.h4
-rw-r--r--drivers/staging/winbond/wblinux.c208
-rw-r--r--drivers/staging/winbond/wblinux_s.h4
-rw-r--r--drivers/staging/wlan-ng/Kconfig2
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h2
-rw-r--r--drivers/staging/wlan-ng/p80211wep.c1
-rw-r--r--drivers/staging/wlan-ng/prism2mib.c2
-rw-r--r--drivers/staging/wlan-ng/wlan_compat.h8
-rw-r--r--drivers/telephony/phonedev.c2
-rw-r--r--drivers/uio/uio.c14
-rw-r--r--drivers/usb/Kconfig5
-rw-r--r--drivers/usb/Makefile3
-rw-r--r--drivers/usb/atm/speedtch.c12
-rw-r--r--drivers/usb/atm/usbatm.c10
-rw-r--r--drivers/usb/atm/usbatm.h10
-rw-r--r--drivers/usb/atm/xusbatm.c2
-rw-r--r--drivers/usb/class/Kconfig10
-rw-r--r--drivers/usb/class/Makefile1
-rw-r--r--drivers/usb/class/cdc-acm.c29
-rw-r--r--drivers/usb/class/cdc-wdm.c50
-rw-r--r--drivers/usb/class/usblp.c25
-rw-r--r--drivers/usb/class/usbtmc.c1087
-rw-r--r--drivers/usb/core/Kconfig2
-rw-r--r--drivers/usb/core/devio.c12
-rw-r--r--drivers/usb/core/driver.c6
-rw-r--r--drivers/usb/core/endpoint.c3
-rw-r--r--drivers/usb/core/file.c5
-rw-r--r--drivers/usb/core/hcd.c4
-rw-r--r--drivers/usb/core/hcd.h6
-rw-r--r--drivers/usb/core/hub.c104
-rw-r--r--drivers/usb/core/inode.c18
-rw-r--r--drivers/usb/core/message.c3
-rw-r--r--drivers/usb/core/sysfs.c24
-rw-r--r--drivers/usb/core/urb.c169
-rw-r--r--drivers/usb/gadget/Kconfig315
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/cdc2.c1
-rw-r--r--drivers/usb/gadget/composite.c68
-rw-r--r--drivers/usb/gadget/config.c2
-rw-r--r--drivers/usb/gadget/dummy_hcd.c33
-rw-r--r--drivers/usb/gadget/ether.c2
-rw-r--r--drivers/usb/gadget/f_loopback.c1
-rw-r--r--drivers/usb/gadget/f_obex.c493
-rw-r--r--drivers/usb/gadget/f_sourcesink.c1
-rw-r--r--drivers/usb/gadget/file_storage.c23
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c2760
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.h437
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.c176
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h21
-rw-r--r--drivers/usb/gadget/gadget_chips.h9
-rw-r--r--drivers/usb/gadget/gmidi.c2
-rw-r--r--drivers/usb/gadget/net2280.c40
-rw-r--r--drivers/usb/gadget/net2280.h1
-rw-r--r--drivers/usb/gadget/omap_udc.c7
-rw-r--r--drivers/usb/gadget/printer.c6
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c3
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c9
-rw-r--r--drivers/usb/gadget/serial.c15
-rw-r--r--drivers/usb/gadget/u_ether.c7
-rw-r--r--drivers/usb/gadget/u_serial.h1
-rw-r--r--drivers/usb/host/Kconfig29
-rw-r--r--drivers/usb/host/Makefile3
-rw-r--r--drivers/usb/host/ehci-dbg.c56
-rw-r--r--drivers/usb/host/ehci-hcd.c48
-rw-r--r--drivers/usb/host/ehci-hub.c27
-rw-r--r--drivers/usb/host/ehci-ppc-soc.c201
-rw-r--r--drivers/usb/host/ehci.h23
-rw-r--r--drivers/usb/host/hwa-hc.c925
-rw-r--r--drivers/usb/host/isp116x-hcd.c13
-rw-r--r--drivers/usb/host/isp1760-if.c7
-rw-r--r--drivers/usb/host/ohci-dbg.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c31
-rw-r--r--drivers/usb/host/ohci-hub.c87
-rw-r--r--drivers/usb/host/ohci-omap.c4
-rw-r--r--drivers/usb/host/ohci-pnx4008.c2
-rw-r--r--drivers/usb/host/ohci-tmio.c376
-rw-r--r--drivers/usb/host/ohci.h8
-rw-r--r--drivers/usb/host/r8a66597-hcd.c101
-rw-r--r--drivers/usb/host/sl811-hcd.c15
-rw-r--r--drivers/usb/host/uhci-hcd.c10
-rw-r--r--drivers/usb/host/uhci-q.c17
-rw-r--r--drivers/usb/host/whci/Kbuild11
-rw-r--r--drivers/usb/host/whci/asl.c367
-rw-r--r--drivers/usb/host/whci/hcd.c339
-rw-r--r--drivers/usb/host/whci/hw.c87
-rw-r--r--drivers/usb/host/whci/init.c188
-rw-r--r--drivers/usb/host/whci/int.c95
-rw-r--r--drivers/usb/host/whci/pzl.c398
-rw-r--r--drivers/usb/host/whci/qset.c567
-rw-r--r--drivers/usb/host/whci/whcd.h197
-rw-r--r--drivers/usb/host/whci/whci-hc.h416
-rw-r--r--drivers/usb/host/whci/wusb.c241
-rw-r--r--drivers/usb/image/mdc800.c61
-rw-r--r--drivers/usb/misc/Kconfig24
-rw-r--r--drivers/usb/misc/Makefile2
-rw-r--r--drivers/usb/misc/adutux.c22
-rw-r--r--drivers/usb/misc/appledisplay.c26
-rw-r--r--drivers/usb/misc/cypress_cy7c63.c6
-rw-r--r--drivers/usb/misc/cytherm.c9
-rw-r--r--drivers/usb/misc/emi26.c17
-rw-r--r--drivers/usb/misc/emi62.c4
-rw-r--r--drivers/usb/misc/ftdi-elan.c10
-rw-r--r--drivers/usb/misc/idmouse.c5
-rw-r--r--drivers/usb/misc/legousbtower.c23
-rw-r--r--drivers/usb/misc/rio500.c11
-rw-r--r--drivers/usb/misc/trancevibrator.c3
-rw-r--r--drivers/usb/misc/usblcd.c13
-rw-r--r--drivers/usb/misc/usbsevseg.c394
-rw-r--r--drivers/usb/misc/usbtest.c3
-rw-r--r--drivers/usb/misc/uss720.c19
-rw-r--r--drivers/usb/misc/vstusb.c782
-rw-r--r--drivers/usb/mon/mon_main.c2
-rw-r--r--drivers/usb/musb/Kconfig4
-rw-r--r--drivers/usb/musb/cppi_dma.h4
-rw-r--r--drivers/usb/musb/davinci.c20
-rw-r--r--drivers/usb/musb/musb_core.c41
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c24
-rw-r--r--drivers/usb/musb/musb_host.c19
-rw-r--r--drivers/usb/musb/musb_io.h4
-rw-r--r--drivers/usb/musb/musbhsdma.c306
-rw-r--r--drivers/usb/serial/aircable.c8
-rw-r--r--drivers/usb/serial/belkin_sa.c39
-rw-r--r--drivers/usb/serial/cp2101.c3
-rw-r--r--drivers/usb/serial/cyberjack.c28
-rw-r--r--drivers/usb/serial/cypress_m8.c21
-rw-r--r--drivers/usb/serial/digi_acceleport.c68
-rw-r--r--drivers/usb/serial/empeg.c11
-rw-r--r--drivers/usb/serial/ezusb.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c82
-rw-r--r--drivers/usb/serial/ftdi_sio.h5
-rw-r--r--drivers/usb/serial/garmin_gps.c3
-rw-r--r--drivers/usb/serial/hp4x.c3
-rw-r--r--drivers/usb/serial/io_edgeport.c19
-rw-r--r--drivers/usb/serial/io_ti.c3
-rw-r--r--drivers/usb/serial/ipaq.c30
-rw-r--r--drivers/usb/serial/ipw.c3
-rw-r--r--drivers/usb/serial/ir-usb.c3
-rw-r--r--drivers/usb/serial/iuu_phoenix.c3
-rw-r--r--drivers/usb/serial/keyspan.c3
-rw-r--r--drivers/usb/serial/keyspan_pda.c17
-rw-r--r--drivers/usb/serial/kl5kusb105.c69
-rw-r--r--drivers/usb/serial/kobil_sct.c4
-rw-r--r--drivers/usb/serial/mct_u232.c42
-rw-r--r--drivers/usb/serial/mos7720.c22
-rw-r--r--drivers/usb/serial/mos7840.c29
-rw-r--r--drivers/usb/serial/omninet.c22
-rw-r--r--drivers/usb/serial/option.c138
-rw-r--r--drivers/usb/serial/pl2303.c2
-rw-r--r--drivers/usb/serial/safe_serial.c28
-rw-r--r--drivers/usb/serial/sierra.c72
-rw-r--r--drivers/usb/serial/spcp8x5.c10
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c4
-rw-r--r--drivers/usb/serial/usb-serial.c26
-rw-r--r--drivers/usb/serial/visor.c17
-rw-r--r--drivers/usb/serial/whiteheat.c121
-rw-r--r--drivers/usb/storage/initializers.c3
-rw-r--r--drivers/usb/storage/onetouch.c9
-rw-r--r--drivers/usb/storage/transport.c2
-rw-r--r--drivers/usb/storage/unusual_devs.h291
-rw-r--r--drivers/usb/wusbcore/Kconfig41
-rw-r--r--drivers/usb/wusbcore/Makefile26
-rw-r--r--drivers/usb/wusbcore/cbaf.c673
-rw-r--r--drivers/usb/wusbcore/crypto.c538
-rw-r--r--drivers/usb/wusbcore/dev-sysfs.c143
-rw-r--r--drivers/usb/wusbcore/devconnect.c1297
-rw-r--r--drivers/usb/wusbcore/mmc.c321
-rw-r--r--drivers/usb/wusbcore/pal.c42
-rw-r--r--drivers/usb/wusbcore/reservation.c115
-rw-r--r--drivers/usb/wusbcore/rh.c477
-rw-r--r--drivers/usb/wusbcore/security.c642
-rw-r--r--drivers/usb/wusbcore/wa-hc.c95
-rw-r--r--drivers/usb/wusbcore/wa-hc.h417
-rw-r--r--drivers/usb/wusbcore/wa-nep.c310
-rw-r--r--drivers/usb/wusbcore/wa-rpipe.c562
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c1709
-rw-r--r--drivers/usb/wusbcore/wusbhc.c418
-rw-r--r--drivers/usb/wusbcore/wusbhc.h495
-rw-r--r--drivers/uwb/Kconfig90
-rw-r--r--drivers/uwb/Makefile29
-rw-r--r--drivers/uwb/address.c374
-rw-r--r--drivers/uwb/beacon.c642
-rw-r--r--drivers/uwb/driver.c144
-rw-r--r--drivers/uwb/drp-avail.c288
-rw-r--r--drivers/uwb/drp-ie.c232
-rw-r--r--drivers/uwb/drp.c461
-rw-r--r--drivers/uwb/est.c477
-rw-r--r--drivers/uwb/hwa-rc.c926
-rw-r--r--drivers/uwb/i1480/Makefile2
-rw-r--r--drivers/uwb/i1480/dfu/Makefile9
-rw-r--r--drivers/uwb/i1480/dfu/dfu.c217
-rw-r--r--drivers/uwb/i1480/dfu/i1480-dfu.h260
-rw-r--r--drivers/uwb/i1480/dfu/mac.c527
-rw-r--r--drivers/uwb/i1480/dfu/phy.c203
-rw-r--r--drivers/uwb/i1480/dfu/usb.c500
-rw-r--r--drivers/uwb/i1480/i1480-est.c99
-rw-r--r--drivers/uwb/i1480/i1480-wlp.h200
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/Makefile8
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h284
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/lc.c421
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/netdev.c368
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/rx.c486
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/sysfs.c408
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/tx.c632
-rw-r--r--drivers/uwb/ie.c541
-rw-r--r--drivers/uwb/lc-dev.c492
-rw-r--r--drivers/uwb/lc-rc.c495
-rw-r--r--drivers/uwb/neh.c616
-rw-r--r--drivers/uwb/pal.c91
-rw-r--r--drivers/uwb/reset.c362
-rw-r--r--drivers/uwb/rsv.c680
-rw-r--r--drivers/uwb/scan.c133
-rw-r--r--drivers/uwb/umc-bus.c218
-rw-r--r--drivers/uwb/umc-dev.c104
-rw-r--r--drivers/uwb/umc-drv.c31
-rw-r--r--drivers/uwb/uwb-debug.c367
-rw-r--r--drivers/uwb/uwb-internal.h305
-rw-r--r--drivers/uwb/uwbd.c410
-rw-r--r--drivers/uwb/whc-rc.c520
-rw-r--r--drivers/uwb/whci.c269
-rw-r--r--drivers/uwb/wlp/Makefile10
-rw-r--r--drivers/uwb/wlp/driver.c43
-rw-r--r--drivers/uwb/wlp/eda.c449
-rw-r--r--drivers/uwb/wlp/messages.c1946
-rw-r--r--drivers/uwb/wlp/sysfs.c709
-rw-r--r--drivers/uwb/wlp/txrx.c374
-rw-r--r--drivers/uwb/wlp/wlp-internal.h228
-rw-r--r--drivers/uwb/wlp/wlp-lc.c585
-rw-r--r--drivers/uwb/wlp/wss-lc.c1055
-rw-r--r--drivers/video/backlight/hp680_bl.c2
-rw-r--r--drivers/video/fbmem.c174
-rw-r--r--drivers/video/imacfb.c0
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c14
-rw-r--r--drivers/w1/slaves/w1_ds2760.c1
-rw-r--r--drivers/watchdog/ib700wdt.c2
-rw-r--r--drivers/watchdog/w83697ug_wdt.c2
-rw-r--r--drivers/xen/cpu_hotplug.c2
-rw-r--r--drivers/xen/events.c18
1099 files changed, 85913 insertions, 19794 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index d19b6f5a110..d38f43f593d 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -78,6 +78,8 @@ source "drivers/hid/Kconfig"
source "drivers/usb/Kconfig"
+source "drivers/uwb/Kconfig"
+
source "drivers/mmc/Kconfig"
source "drivers/memstick/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 46c8681a07f..2503f7b99b2 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_EISA) += eisa/
obj-y += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_CPU_IDLE) += cpuidle/
+obj-y += idle/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_MEMSTICK) += memstick/
obj-$(CONFIG_NEW_LEDS) += leds/
@@ -100,3 +101,4 @@ obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_REGULATOR) += regulator/
obj-$(CONFIG_STAGING) += staging/
+obj-$(CONFIG_UWB) += uwb/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index da49b006bcc..f4f63291750 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -42,7 +42,7 @@ if ACPI
config ACPI_SLEEP
bool
- depends on PM_SLEEP
+ depends on SUSPEND || HIBERNATION
default y
config ACPI_PROCFS
@@ -157,18 +157,11 @@ config ACPI_FAN
applications to perform basic fan control (on, off, status).
config ACPI_DOCK
- tristate "Dock"
+ bool "Dock"
depends on EXPERIMENTAL
help
- This driver adds support for ACPI controlled docking stations
-
-config ACPI_BAY
- tristate "Removable Drive Bay (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- depends on ACPI_DOCK
- help
- This driver adds support for ACPI controlled removable drive
- bays such as the IBM ultrabay or the Dell Module Bay.
+ This driver adds support for ACPI controlled docking stations and removable
+ drive bays such as the IBM ultrabay or the Dell Module Bay.
config ACPI_PROCESSOR
tristate "Processor"
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 52a4cd4b81d..d91c027ece8 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -45,14 +45,13 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_DOCK) += dock.o
-obj-$(CONFIG_ACPI_BAY) += bay.o
obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
-obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
obj-$(CONFIG_ACPI_CONTAINER) += container.o
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
+obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
obj-$(CONFIG_ACPI_DEBUG) += debug.o
obj-$(CONFIG_ACPI_NUMA) += numa.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 831883b7d6c..d72a1b6c8a9 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -85,7 +85,7 @@ struct acpi_ac {
struct power_supply charger;
#endif
struct acpi_device * device;
- unsigned long state;
+ unsigned long long state;
};
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger);
@@ -269,7 +269,7 @@ static int acpi_ac_add(struct acpi_device *device)
ac->device = device;
strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_AC_CLASS);
- acpi_driver_data(device) = ac;
+ device->driver_data = ac;
result = acpi_ac_get_state(ac);
if (result)
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 5f1127ad5a9..71d21c51c45 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -194,8 +194,7 @@ acpi_memory_get_device(acpi_handle handle,
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
{
- unsigned long current_status;
-
+ unsigned long long current_status;
/* Get device present/absent information from the _STA */
if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA",
@@ -264,7 +263,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
acpi_status status;
struct acpi_object_list arg_list;
union acpi_object arg;
- unsigned long current_status;
+ unsigned long long current_status;
/* Issue the _EJ0 command */
@@ -403,7 +402,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
mem_device->device = device;
sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
- acpi_driver_data(device) = mem_device;
+ device->driver_data = mem_device;
/* Get the range from the _CRS */
result = acpi_memory_get_device_resources(mem_device);
@@ -454,8 +453,8 @@ static int acpi_memory_device_start (struct acpi_device *device)
/* call add_memory func */
result = acpi_memory_enable_device(mem_device);
if (result)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error in acpi_memory_enable_device\n"));
+ printk(KERN_ERR PREFIX
+ "Error in acpi_memory_enable_device\n");
}
return result;
}
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index d3d0886d637..1e74988c7b2 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -42,7 +42,7 @@
#define ASUS_ACPI_VERSION "0.30"
-#define PROC_ASUS "asus" //the directory
+#define PROC_ASUS "asus" /* The directory */
#define PROC_MLED "mled"
#define PROC_WLED "wled"
#define PROC_TLED "tled"
@@ -66,10 +66,10 @@
/*
* Flags for hotk status
*/
-#define MLED_ON 0x01 //mail LED
-#define WLED_ON 0x02 //wireless LED
-#define TLED_ON 0x04 //touchpad LED
-#define BT_ON 0x08 //internal Bluetooth
+#define MLED_ON 0x01 /* Mail LED */
+#define WLED_ON 0x02 /* Wireless LED */
+#define TLED_ON 0x04 /* Touchpad LED */
+#define BT_ON 0x08 /* Internal Bluetooth */
MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
MODULE_DESCRIPTION(ACPI_HOTK_NAME);
@@ -82,28 +82,28 @@ MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus");
module_param(asus_gid, uint, 0);
MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus");
-/* For each model, all features implemented,
+/* For each model, all features implemented,
* those marked with R are relative to HOTK, A for absolute */
struct model_data {
- char *name; //name of the laptop________________A
- char *mt_mled; //method to handle mled_____________R
- char *mled_status; //node to handle mled reading_______A
- char *mt_wled; //method to handle wled_____________R
- char *wled_status; //node to handle wled reading_______A
- char *mt_tled; //method to handle tled_____________R
- char *tled_status; //node to handle tled reading_______A
- char *mt_ledd; //method to handle LED display______R
- char *mt_bt_switch; //method to switch Bluetooth on/off_R
- char *bt_status; //no model currently supports this__?
- char *mt_lcd_switch; //method to turn LCD on/off_________A
- char *lcd_status; //node to read LCD panel state______A
- char *brightness_up; //method to set brightness up_______A
- char *brightness_down; //guess what ?______________________A
- char *brightness_set; //method to set absolute brightness_R
- char *brightness_get; //method to get absolute brightness_R
- char *brightness_status; //node to get brightness____________A
- char *display_set; //method to set video output________R
- char *display_get; //method to get video output________R
+ char *name; /* name of the laptop________________A */
+ char *mt_mled; /* method to handle mled_____________R */
+ char *mled_status; /* node to handle mled reading_______A */
+ char *mt_wled; /* method to handle wled_____________R */
+ char *wled_status; /* node to handle wled reading_______A */
+ char *mt_tled; /* method to handle tled_____________R */
+ char *tled_status; /* node to handle tled reading_______A */
+ char *mt_ledd; /* method to handle LED display______R */
+ char *mt_bt_switch; /* method to switch Bluetooth on/off_R */
+ char *bt_status; /* no model currently supports this__? */
+ char *mt_lcd_switch; /* method to turn LCD on/off_________A */
+ char *lcd_status; /* node to read LCD panel state______A */
+ char *brightness_up; /* method to set brightness up_______A */
+ char *brightness_down; /* method to set brightness down ____A */
+ char *brightness_set; /* method to set absolute brightness_R */
+ char *brightness_get; /* method to get absolute brightness_R */
+ char *brightness_status;/* node to get brightness____________A */
+ char *display_set; /* method to set video output________R */
+ char *display_get; /* method to get video output________R */
};
/*
@@ -111,41 +111,41 @@ struct model_data {
* about the hotk device
*/
struct asus_hotk {
- struct acpi_device *device; //the device we are in
- acpi_handle handle; //the handle of the hotk device
- char status; //status of the hotk, for LEDs, ...
- u32 ledd_status; //status of the LED display
- struct model_data *methods; //methods available on the laptop
- u8 brightness; //brightness level
+ struct acpi_device *device; /* the device we are in */
+ acpi_handle handle; /* the handle of the hotk device */
+ char status; /* status of the hotk, for LEDs */
+ u32 ledd_status; /* status of the LED display */
+ struct model_data *methods; /* methods available on the laptop */
+ u8 brightness; /* brightness level */
enum {
- A1x = 0, //A1340D, A1300F
- A2x, //A2500H
- A4G, //A4700G
- D1x, //D1
- L2D, //L2000D
- L3C, //L3800C
- L3D, //L3400D
- L3H, //L3H, L2000E, L5D
- L4R, //L4500R
- L5x, //L5800C
- L8L, //L8400L
- M1A, //M1300A
- M2E, //M2400E, L4400L
- M6N, //M6800N, W3400N
- M6R, //M6700R, A3000G
- P30, //Samsung P30
- S1x, //S1300A, but also L1400B and M2400A (L84F)
- S2x, //S200 (J1 reported), Victor MP-XP7210
- W1N, //W1000N
- W5A, //W5A
- W3V, //W3030V
- xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
- A4S, //Z81sp
- //(Centrino)
- F3Sa,
+ A1x = 0, /* A1340D, A1300F */
+ A2x, /* A2500H */
+ A4G, /* A4700G */
+ D1x, /* D1 */
+ L2D, /* L2000D */
+ L3C, /* L3800C */
+ L3D, /* L3400D */
+ L3H, /* L3H, L2000E, L5D */
+ L4R, /* L4500R */
+ L5x, /* L5800C */
+ L8L, /* L8400L */
+ M1A, /* M1300A */
+ M2E, /* M2400E, L4400L */
+ M6N, /* M6800N, W3400N */
+ M6R, /* M6700R, A3000G */
+ P30, /* Samsung P30 */
+ S1x, /* S1300A, but also L1400B and M2400A (L84F) */
+ S2x, /* S200 (J1 reported), Victor MP-XP7210 */
+ W1N, /* W1000N */
+ W5A, /* W5A */
+ W3V, /* W3030V */
+ xxN, /* M2400N, M3700N, M5200N, M6800N,
+ S1300N, S5200N*/
+ A4S, /* Z81sp */
+ F3Sa, /* (Centrino) */
END_MODEL
- } model; //Models currently supported
- u16 event_count[128]; //count for each event TODO make this better
+ } model; /* Models currently supported */
+ u16 event_count[128]; /* Count for each event TODO make this better */
};
/* Here we go */
@@ -459,18 +459,18 @@ static struct acpi_driver asus_hotk_driver = {
},
};
-/*
+/*
* This function evaluates an ACPI method, given an int as parameter, the
* method is searched within the scope of the handle, can be NULL. The output
* of the method is written is output, which can also be NULL
*
- * returns 1 if write is successful, 0 else.
+ * returns 1 if write is successful, 0 else.
*/
static int write_acpi_int(acpi_handle handle, const char *method, int val,
struct acpi_buffer *output)
{
- struct acpi_object_list params; //list of input parameters (an int here)
- union acpi_object in_obj; //the only param we use
+ struct acpi_object_list params; /* list of input parameters (int) */
+ union acpi_object in_obj; /* the only param we use */
acpi_status status;
params.count = 1;
@@ -507,18 +507,18 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof,
{
int len = 0;
int temp;
- char buf[16]; //enough for all info
+ char buf[16]; /* enough for all info */
/*
- * We use the easy way, we don't care of off and count, so we don't set eof
- * to 1
+ * We use the easy way, we don't care of off and count,
+ * so we don't set eof to 1
*/
len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
len += sprintf(page + len, "Model reference : %s\n",
hotk->methods->name);
- /*
- * The SFUN method probably allows the original driver to get the list
- * of features supported by a given model. For now, 0x0100 or 0x0800
+ /*
+ * The SFUN method probably allows the original driver to get the list
+ * of features supported by a given model. For now, 0x0100 or 0x0800
* bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
* The significance of others is yet to be found.
*/
@@ -528,7 +528,7 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof,
/*
* Another value for userspace: the ASYM method returns 0x02 for
* battery low and 0x04 for battery critical, its readings tend to be
- * more accurate than those provided by _BST.
+ * more accurate than those provided by _BST.
* Note: since not all the laptops provide this method, errors are
* silently ignored.
*/
@@ -579,7 +579,7 @@ static int read_led(const char *ledname, int ledmask)
return (hotk->status & ledmask) ? 1 : 0;
}
-static int parse_arg(const char __user * buf, unsigned long count, int *val)
+static int parse_arg(const char __user *buf, unsigned long count, int *val)
{
char s[32];
if (!count)
@@ -596,7 +596,7 @@ static int parse_arg(const char __user * buf, unsigned long count, int *val)
/* FIXME: kill extraneous args so it can be called independently */
static int
-write_led(const char __user * buffer, unsigned long count,
+write_led(const char __user *buffer, unsigned long count,
char *ledname, int ledmask, int invert)
{
int rv, value;
@@ -631,7 +631,7 @@ proc_read_mled(char *page, char **start, off_t off, int count, int *eof,
}
static int
-proc_write_mled(struct file *file, const char __user * buffer,
+proc_write_mled(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
@@ -648,7 +648,7 @@ proc_read_ledd(char *page, char **start, off_t off, int count, int *eof,
}
static int
-proc_write_ledd(struct file *file, const char __user * buffer,
+proc_write_ledd(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
int rv, value;
@@ -677,7 +677,7 @@ proc_read_wled(char *page, char **start, off_t off, int count, int *eof,
}
static int
-proc_write_wled(struct file *file, const char __user * buffer,
+proc_write_wled(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
@@ -694,10 +694,10 @@ proc_read_bluetooth(char *page, char **start, off_t off, int count, int *eof,
}
static int
-proc_write_bluetooth(struct file *file, const char __user * buffer,
+proc_write_bluetooth(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
- /* Note: mt_bt_switch controls both internal Bluetooth adapter's
+ /* Note: mt_bt_switch controls both internal Bluetooth adapter's
presence and its LED */
return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
}
@@ -714,7 +714,7 @@ proc_read_tled(char *page, char **start, off_t off, int count, int *eof,
}
static int
-proc_write_tled(struct file *file, const char __user * buffer,
+proc_write_tled(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
@@ -734,7 +734,7 @@ static int get_lcd_state(void)
input.count = 2;
input.pointer = mt_params;
- /* Note: the following values are partly guessed up, but
+ /* Note: the following values are partly guessed up, but
otherwise they seem to work */
mt_params[0].type = ACPI_TYPE_INTEGER;
mt_params[0].integer.value = 0x02;
@@ -753,7 +753,7 @@ static int get_lcd_state(void)
/* That's what the AML code does */
lcd = out_obj.integer.value >> 8;
} else if (hotk->model == F3Sa) {
- unsigned long tmp;
+ unsigned long long tmp;
union acpi_object param;
struct acpi_object_list input;
acpi_status status;
@@ -796,12 +796,13 @@ static int set_lcd_state(int value)
acpi_evaluate_object(NULL,
hotk->methods->mt_lcd_switch,
NULL, NULL);
- } else { /* L3H and the like have to be handled differently */
+ } else {
+ /* L3H and the like must be handled differently */
if (!write_acpi_int
(hotk->handle, hotk->methods->mt_lcd_switch, 0x07,
NULL))
status = AE_ERROR;
- /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
+ /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
the exact behaviour is simulated here */
}
if (ACPI_FAILURE(status))
@@ -819,7 +820,7 @@ proc_read_lcd(char *page, char **start, off_t off, int count, int *eof,
}
static int
-proc_write_lcd(struct file *file, const char __user * buffer,
+proc_write_lcd(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
int rv, value;
@@ -897,7 +898,7 @@ proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
}
static int
-proc_write_brn(struct file *file, const char __user * buffer,
+proc_write_brn(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
int rv, value;
@@ -921,7 +922,7 @@ static void set_display(int value)
}
/*
- * Now, *this* one could be more user-friendly, but so far, no-one has
+ * Now, *this* one could be more user-friendly, but so far, no-one has
* complained. The significance of bits is the same as in proc_write_disp()
*/
static int
@@ -933,18 +934,18 @@ proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
printk(KERN_WARNING
"Asus ACPI: Error reading display status\n");
- value &= 0x07; /* needed for some models, shouldn't hurt others */
+ value &= 0x07; /* needed for some models, shouldn't hurt others */
return sprintf(page, "%d\n", value);
}
/*
- * Experimental support for display switching. As of now: 1 should activate
- * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
- * (bitwise) of these will suffice. I never actually tested 3 displays hooked up
- * simultaneously, so be warned. See the acpi4asus README for more info.
+ * Experimental support for display switching. As of now: 1 should activate
+ * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
+ * (bitwise) of these will suffice. I never actually tested 3 displays hooked
+ * up simultaneously, so be warned. See the acpi4asus README for more info.
*/
static int
-proc_write_disp(struct file *file, const char __user * buffer,
+proc_write_disp(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
int rv, value;
@@ -957,12 +958,12 @@ proc_write_disp(struct file *file, const char __user * buffer,
typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
int *eof, void *data);
-typedef int (proc_writefunc) (struct file * file, const char __user * buffer,
+typedef int (proc_writefunc) (struct file *file, const char __user *buffer,
unsigned long count, void *data);
static int
-asus_proc_add(char *name, proc_writefunc * writefunc,
- proc_readfunc * readfunc, mode_t mode,
+asus_proc_add(char *name, proc_writefunc *writefunc,
+ proc_readfunc *readfunc, mode_t mode,
struct acpi_device *device)
{
struct proc_dir_entry *proc =
@@ -1040,9 +1041,9 @@ static int asus_hotk_add_fs(struct acpi_device *device)
&proc_read_bluetooth, mode, device);
}
- /*
- * We need both read node and write method as LCD switch is also accessible
- * from keyboard
+ /*
+ * We need both read node and write method as LCD switch is also
+ * accessible from the keyboard
*/
if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode,
@@ -1096,11 +1097,10 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
if (!hotk)
return;
- if ((event & ~((u32) BR_UP)) < 16) {
+ if ((event & ~((u32) BR_UP)) < 16)
hotk->brightness = (event & ~((u32) BR_UP));
- } else if ((event & ~((u32) BR_DOWN)) < 16) {
+ else if ((event & ~((u32) BR_DOWN)) < 16)
hotk->brightness = (event & ~((u32) BR_DOWN));
- }
acpi_bus_generate_proc_event(hotk->device, event,
hotk->event_count[event % 128]++);
@@ -1186,8 +1186,8 @@ static int asus_hotk_get_info(void)
acpi_status status;
/*
- * Get DSDT headers early enough to allow for differentiating between
- * models, but late enough to allow acpi_bus_register_driver() to fail
+ * Get DSDT headers early enough to allow for differentiating between
+ * models, but late enough to allow acpi_bus_register_driver() to fail
* before doing anything ACPI-specific. Should we encounter a machine,
* which needs special handling (i.e. its hotkey device has a different
* HID), this bit will be moved. A global variable asus_info contains
@@ -1212,8 +1212,8 @@ static int asus_hotk_get_info(void)
/*
* Try to match the object returned by INIT to the specific model.
- * Handle every possible object (or the lack of thereof) the DSDT
- * writers might throw at us. When in trouble, we pass NULL to
+ * Handle every possible object (or the lack of thereof) the DSDT
+ * writers might throw at us. When in trouble, we pass NULL to
* asus_model_match() and try something completely different.
*/
if (buffer.pointer) {
@@ -1244,6 +1244,8 @@ static int asus_hotk_get_info(void)
"default values\n", string);
printk(KERN_NOTICE
" send /proc/acpi/dsdt to the developers\n");
+ kfree(model);
+ return -ENODEV;
}
hotk->methods = &model_conf[hotk->model];
return AE_OK;
@@ -1254,7 +1256,7 @@ static int asus_hotk_get_info(void)
/* Sort of per-model blacklist */
if (strncmp(string, "L2B", 3) == 0)
hotk->methods->lcd_status = NULL;
- /* L2B is similar enough to L3C to use its settings, with this only
+ /* L2B is similar enough to L3C to use its settings, with this only
exception */
else if (strncmp(string, "A3G", 3) == 0)
hotk->methods->lcd_status = "\\BLFG";
@@ -1321,7 +1323,7 @@ static int asus_hotk_add(struct acpi_device *device)
hotk->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
- acpi_driver_data(device) = hotk;
+ device->driver_data = hotk;
hotk->device = device;
result = asus_hotk_check();
@@ -1366,10 +1368,9 @@ static int asus_hotk_add(struct acpi_device *device)
/* LED display is off by default */
hotk->ledd_status = 0xFFF;
- end:
- if (result) {
+end:
+ if (result)
kfree(hotk);
- }
return result;
}
@@ -1394,8 +1395,8 @@ static int asus_hotk_remove(struct acpi_device *device, int type)
}
static struct backlight_ops asus_backlight_data = {
- .get_brightness = read_brightness,
- .update_status = set_brightness_status,
+ .get_brightness = read_brightness,
+ .update_status = set_brightness_status,
};
static void asus_acpi_exit(void)
@@ -1442,15 +1443,15 @@ static int __init asus_acpi_init(void)
return -ENODEV;
}
- asus_backlight_device = backlight_device_register("asus",NULL,NULL,
+ asus_backlight_device = backlight_device_register("asus", NULL, NULL,
&asus_backlight_data);
- if (IS_ERR(asus_backlight_device)) {
+ if (IS_ERR(asus_backlight_device)) {
printk(KERN_ERR "Could not register asus backlight device\n");
asus_backlight_device = NULL;
asus_acpi_exit();
return -ENODEV;
}
- asus_backlight_device->props.max_brightness = 15;
+ asus_backlight_device->props.max_brightness = 15;
return 0;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index b1c723f9f58..b2133e89ad9 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -431,7 +431,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev,
}
static struct device_attribute alarm_attr = {
- .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
+ .attr = {.name = "alarm", .mode = 0644},
.show = acpi_battery_alarm_show,
.store = acpi_battery_alarm_store,
};
@@ -804,7 +804,7 @@ static int acpi_battery_add(struct acpi_device *device)
battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
- acpi_driver_data(device) = battery;
+ device->driver_data = battery;
mutex_init(&battery->lock);
acpi_battery_update(battery);
#ifdef CONFIG_ACPI_PROCFS_POWER
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
deleted file mode 100644
index 61b6c5beb2d..00000000000
--- a/drivers/acpi/bay.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * bay.c - ACPI removable drive bay driver
- *
- * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/notifier.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-#include <linux/seq_file.h>
-#include <asm/uaccess.h>
-#include <linux/platform_device.h>
-
-ACPI_MODULE_NAME("bay");
-MODULE_AUTHOR("Kristen Carlson Accardi");
-MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver");
-MODULE_LICENSE("GPL");
-#define ACPI_BAY_CLASS "bay"
-#define ACPI_BAY_COMPONENT 0x10000000
-#define _COMPONENT ACPI_BAY_COMPONENT
-#define bay_dprintk(h,s) {\
- char prefix[80] = {'\0'};\
- struct acpi_buffer buffer = {sizeof(prefix), prefix};\
- acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
- printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
-static void bay_notify(acpi_handle handle, u32 event, void *data);
-
-static const struct acpi_device_id bay_device_ids[] = {
- {"LNXIOBAY", 0},
- {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, bay_device_ids);
-
-struct bay {
- acpi_handle handle;
- char *name;
- struct list_head list;
- struct platform_device *pdev;
-};
-
-static LIST_HEAD(drive_bays);
-
-
-/*****************************************************************************
- * Drive Bay functions *
- *****************************************************************************/
-/**
- * is_ejectable - see if a device is ejectable
- * @handle: acpi handle of the device
- *
- * If an acpi object has a _EJ0 method, then it is ejectable
- */
-static int is_ejectable(acpi_handle handle)
-{
- acpi_status status;
- acpi_handle tmp;
-
- status = acpi_get_handle(handle, "_EJ0", &tmp);
- if (ACPI_FAILURE(status))
- return 0;
- return 1;
-}
-
-/**
- * bay_present - see if the bay device is present
- * @bay: the drive bay
- *
- * execute the _STA method.
- */
-static int bay_present(struct bay *bay)
-{
- unsigned long sta;
- acpi_status status;
-
- if (bay) {
- status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
- if (ACPI_SUCCESS(status) && sta)
- return 1;
- }
- return 0;
-}
-
-/**
- * eject_device - respond to an eject request
- * @handle - the device to eject
- *
- * Call this devices _EJ0 method.
- */
-static void eject_device(acpi_handle handle)
-{
- struct acpi_object_list arg_list;
- union acpi_object arg;
-
- bay_dprintk(handle, "Ejecting device");
-
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
-
- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
- &arg_list, NULL)))
- pr_debug("Failed to evaluate _EJ0!\n");
-}
-
-/*
- * show_present - read method for "present" file in sysfs
- */
-static ssize_t show_present(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct bay *bay = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
-
-}
-static DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
-
-/*
- * write_eject - write method for "eject" file in sysfs
- */
-static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct bay *bay = dev_get_drvdata(dev);
-
- if (!count)
- return -EINVAL;
-
- eject_device(bay->handle);
- return count;
-}
-static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
-
-/**
- * is_ata - see if a device is an ata device
- * @handle: acpi handle of the device
- *
- * If an acpi object has one of 4 ATA ACPI methods defined,
- * then it is an ATA device
- */
-static int is_ata(acpi_handle handle)
-{
- acpi_handle tmp;
-
- if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
- return 1;
-
- return 0;
-}
-
-/**
- * parent_is_ata(acpi_handle handle)
- *
- */
-static int parent_is_ata(acpi_handle handle)
-{
- acpi_handle phandle;
-
- if (acpi_get_parent(handle, &phandle))
- return 0;
-
- return is_ata(phandle);
-}
-
-/**
- * is_ejectable_bay - see if a device is an ejectable drive bay
- * @handle: acpi handle of the device
- *
- * If an acpi object is ejectable and has one of the ACPI ATA
- * methods defined, then we can safely call it an ejectable
- * drive bay
- */
-static int is_ejectable_bay(acpi_handle handle)
-{
- if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
- return 1;
- return 0;
-}
-
-#if 0
-/**
- * eject_removable_drive - try to eject this drive
- * @dev : the device structure of the drive
- *
- * If a device is a removable drive that requires an _EJ0 method
- * to be executed in order to safely remove from the system, do
- * it. ATM - always returns success
- */
-int eject_removable_drive(struct device *dev)
-{
- acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
-
- if (handle) {
- bay_dprintk(handle, "Got device handle");
- if (is_ejectable_bay(handle))
- eject_device(handle);
- } else {
- printk("No acpi handle for device\n");
- }
-
- /* should I return an error code? */
- return 0;
-}
-EXPORT_SYMBOL_GPL(eject_removable_drive);
-#endif /* 0 */
-
-static int acpi_bay_add_fs(struct bay *bay)
-{
- int ret;
- struct device *dev = &bay->pdev->dev;
-
- ret = device_create_file(dev, &dev_attr_present);
- if (ret)
- goto add_fs_err;
- ret = device_create_file(dev, &dev_attr_eject);
- if (ret) {
- device_remove_file(dev, &dev_attr_present);
- goto add_fs_err;
- }
- return 0;
-
- add_fs_err:
- bay_dprintk(bay->handle, "Error adding sysfs files\n");
- return ret;
-}
-
-static void acpi_bay_remove_fs(struct bay *bay)
-{
- struct device *dev = &bay->pdev->dev;
-
- /* cleanup sysfs */
- device_remove_file(dev, &dev_attr_present);
- device_remove_file(dev, &dev_attr_eject);
-}
-
-static int bay_is_dock_device(acpi_handle handle)
-{
- acpi_handle parent;
-
- acpi_get_parent(handle, &parent);
-
- /* if the device or it's parent is dependent on the
- * dock, then we are a dock device
- */
- return (is_dock_device(handle) || is_dock_device(parent));
-}
-
-static int bay_add(acpi_handle handle, int id)
-{
- acpi_status status;
- struct bay *new_bay;
- struct platform_device *pdev;
- struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
-
- bay_dprintk(handle, "Adding notify handler");
-
- /*
- * Initialize bay device structure
- */
- new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC);
- INIT_LIST_HEAD(&new_bay->list);
- new_bay->handle = handle;
- new_bay->name = (char *)nbuffer.pointer;
-
- /* initialize platform device stuff */
- pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
- if (IS_ERR(pdev)) {
- printk(KERN_ERR PREFIX "Error registering bay device\n");
- goto bay_add_err;
- }
- new_bay->pdev = pdev;
- platform_set_drvdata(pdev, new_bay);
-
- /*
- * we want the bay driver to be able to send uevents
- */
- pdev->dev.uevent_suppress = 0;
-
- /* register for events on this device */
- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- bay_notify, new_bay);
- if (ACPI_FAILURE(status)) {
- printk(KERN_INFO PREFIX "Error installing bay notify handler\n");
- platform_device_unregister(new_bay->pdev);
- goto bay_add_err;
- }
-
- if (acpi_bay_add_fs(new_bay)) {
- acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- bay_notify);
- platform_device_unregister(new_bay->pdev);
- goto bay_add_err;
- }
-
- /* if we are on a dock station, we should register for dock
- * notifications.
- */
- if (bay_is_dock_device(handle)) {
- bay_dprintk(handle, "Is dependent on dock\n");
- register_hotplug_dock_device(handle, bay_notify, new_bay);
- }
- list_add(&new_bay->list, &drive_bays);
- printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
- return 0;
-
-bay_add_err:
- kfree(new_bay->name);
- kfree(new_bay);
- return -ENODEV;
-}
-
-/**
- * bay_notify - act upon an acpi bay notification
- * @handle: the bay handle
- * @event: the acpi event
- * @data: our driver data struct
- *
- */
-static void bay_notify(acpi_handle handle, u32 event, void *data)
-{
- struct bay *bay_dev = (struct bay *)data;
- struct device *dev = &bay_dev->pdev->dev;
- char event_string[12];
- char *envp[] = { event_string, NULL };
-
- bay_dprintk(handle, "Bay event");
- sprintf(event_string, "BAY_EVENT=%d", event);
- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
-}
-
-static acpi_status
-find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- int *count = (int *)context;
-
- /*
- * there could be more than one ejectable bay.
- * so, just return AE_OK always so that every object
- * will be checked.
- */
- if (is_ejectable_bay(handle)) {
- bay_dprintk(handle, "found ejectable bay");
- if (!bay_add(handle, *count))
- (*count)++;
- }
- return AE_OK;
-}
-
-static int __init bay_init(void)
-{
- int bays = 0;
-
- INIT_LIST_HEAD(&drive_bays);
-
- if (acpi_disabled)
- return -ENODEV;
-
- /* look for dockable drive bays */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, find_bay, &bays, NULL);
-
- if (!bays)
- return -ENODEV;
-
- return 0;
-}
-
-static void __exit bay_exit(void)
-{
- struct bay *bay, *tmp;
-
- list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
- if (is_dock_device(bay->handle))
- unregister_hotplug_dock_device(bay->handle);
- acpi_bay_remove_fs(bay);
- acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
- bay_notify);
- platform_device_unregister(bay->pdev);
- kfree(bay->name);
- kfree(bay);
- }
-}
-
-postcore_initcall(bay_init);
-module_exit(bay_exit);
-
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index ccae305ee55..c797c6473f3 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -48,6 +48,23 @@ EXPORT_SYMBOL(acpi_root_dir);
#define STRUCT_TO_INT(s) (*((int*)&s))
+static int set_power_nocheck(const struct dmi_system_id *id)
+{
+ printk(KERN_NOTICE PREFIX "%s detected - "
+ "disable power check in power transistion\n", id->ident);
+ acpi_power_nocheck = 1;
+ return 0;
+}
+static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = {
+ {
+ set_power_nocheck, "HP Pavilion 05", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL},
+ {},
+};
+
+
/* --------------------------------------------------------------------------
Device Management
-------------------------------------------------------------------------- */
@@ -77,7 +94,7 @@ EXPORT_SYMBOL(acpi_bus_get_device);
int acpi_bus_get_status(struct acpi_device *device)
{
acpi_status status = AE_OK;
- unsigned long sta = 0;
+ unsigned long long sta = 0;
if (!device)
@@ -95,21 +112,21 @@ int acpi_bus_get_status(struct acpi_device *device)
}
/*
- * Otherwise we assume the status of our parent (unless we don't
- * have one, in which case status is implied).
+ * According to ACPI spec some device can be present and functional
+ * even if the parent is not present but functional.
+ * In such conditions the child device should not inherit the status
+ * from the parent.
*/
- else if (device->parent)
- device->status = device->parent->status;
else
STRUCT_TO_INT(device->status) =
ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
if (device->status.functional && !device->status.present) {
- printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
- "functional but not present; setting present\n",
- device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status));
- device->status.present = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
+ "functional but not present;\n",
+ device->pnp.bus_id,
+ (u32) STRUCT_TO_INT(device->status)));
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
@@ -155,7 +172,7 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
int result = 0;
acpi_status status = 0;
struct acpi_device *device = NULL;
- unsigned long psc = 0;
+ unsigned long long psc = 0;
result = acpi_bus_get_device(handle, &device);
@@ -223,7 +240,19 @@ int acpi_bus_set_power(acpi_handle handle, int state)
/*
* Get device's current power state
*/
- acpi_bus_get_power(device->handle, &device->power.state);
+ if (!acpi_power_nocheck) {
+ /*
+ * Maybe the incorrect power state is returned on the bogus
+ * bios, which is different with the real power state.
+ * For example: the bios returns D0 state and the real power
+ * state is D3. OS expects to set the device to D0 state. In
+ * such case if OS uses the power state returned by the BIOS,
+ * the device can't be transisted to the correct power state.
+ * So if the acpi_power_nocheck is set, it is unnecessary to
+ * get the power state by calling acpi_bus_get_power.
+ */
+ acpi_bus_get_power(device->handle, &device->power.state);
+ }
if ((state == device->power.state) && !device->flags.force_power_state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
state));
@@ -496,6 +525,19 @@ static int acpi_bus_check_scope(struct acpi_device *device)
return 0;
}
+static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
+int register_acpi_bus_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
+
+void unregister_acpi_bus_notifier(struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
+
/**
* acpi_bus_notify
* ---------------
@@ -506,6 +548,8 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
int result = 0;
struct acpi_device *device = NULL;
+ blocking_notifier_call_chain(&acpi_bus_notify_list,
+ type, (void *)handle);
if (acpi_bus_get_device(handle, &device))
return;
@@ -749,6 +793,12 @@ static int __init acpi_bus_init(void)
goto error1;
}
+ /*
+ * Maybe EC region is required at bus_scan/acpi_get_devices. So it
+ * is necessary to enable it as early as possible.
+ */
+ acpi_boot_ec_enable();
+
printk(KERN_INFO PREFIX "Interpreter enabled\n");
/* Initialize sleep structures */
@@ -818,7 +868,11 @@ static int __init acpi_init(void)
}
} else
disable_acpi();
-
+ /*
+ * If the laptop falls into the DMI check table, the power state check
+ * will be disabled in the course of device power transistion.
+ */
+ dmi_check_system(power_nocheck_dmi_table);
return result;
}
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 1dfec413588..9d568d417ea 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -145,7 +145,7 @@ static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_button *button = seq->private;
acpi_status status;
- unsigned long state;
+ unsigned long long state;
if (!button || !button->device)
return 0;
@@ -253,7 +253,7 @@ static int acpi_button_remove_fs(struct acpi_device *device)
-------------------------------------------------------------------------- */
static int acpi_lid_send_state(struct acpi_button *button)
{
- unsigned long state;
+ unsigned long long state;
acpi_status status;
status = acpi_evaluate_integer(button->device->handle, "_LID", NULL,
@@ -384,7 +384,7 @@ static int acpi_button_add(struct acpi_device *device)
return -ENOMEM;
button->device = device;
- acpi_driver_data(device) = button;
+ device->driver_data = button;
button->input = input = input_allocate_device();
if (!input) {
diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c
index f9db4f444bd..4441e84b28a 100644
--- a/drivers/acpi/cm_sbs.c
+++ b/drivers/acpi/cm_sbs.c
@@ -52,8 +52,8 @@ struct proc_dir_entry *acpi_lock_ac_dir(void)
if (acpi_ac_dir) {
lock_ac_dir_cnt++;
} else {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Cannot create %s\n", ACPI_AC_CLASS));
+ printk(KERN_ERR PREFIX
+ "Cannot create %s\n", ACPI_AC_CLASS);
}
mutex_unlock(&cm_sbs_mutex);
return acpi_ac_dir;
@@ -83,8 +83,8 @@ struct proc_dir_entry *acpi_lock_battery_dir(void)
if (acpi_battery_dir) {
lock_battery_dir_cnt++;
} else {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Cannot create %s\n", ACPI_BATTERY_CLASS));
+ printk(KERN_ERR PREFIX
+ "Cannot create %s\n", ACPI_BATTERY_CLASS);
}
mutex_unlock(&cm_sbs_mutex);
return acpi_battery_dir;
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 3c25ec7a187..134818b265a 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -76,7 +76,7 @@ static int is_device_present(acpi_handle handle)
{
acpi_handle temp;
acpi_status status;
- unsigned long sta;
+ unsigned long long sta;
status = acpi_get_handle(handle, "_STA", &temp);
@@ -108,7 +108,7 @@ static int acpi_container_add(struct acpi_device *device)
container->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
- acpi_driver_data(device) = container;
+ device->driver_data = container;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
acpi_device_name(device), acpi_device_bid(device)));
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index 6df564f4ca6..abf36b4b1d1 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -47,8 +47,6 @@ static const struct acpi_dlayer acpi_debug_layers[] = {
};
static const struct acpi_dlevel acpi_debug_levels[] = {
- ACPI_DEBUG_INIT(ACPI_LV_ERROR),
- ACPI_DEBUG_INIT(ACPI_LV_WARN),
ACPI_DEBUG_INIT(ACPI_LV_INIT),
ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT),
ACPI_DEBUG_INIT(ACPI_LV_INFO),
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index 4613b9ca579..279a5a60a0d 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -103,6 +103,9 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
NULL);
acpi_ex_enter_interpreter();
}
+
+ acpi_ds_clear_implicit_return(walk_state);
+
#ifdef ACPI_DISASSEMBLER
if (ACPI_FAILURE(status)) {
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index 13c43eac35d..d03f81bd1bc 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -43,7 +43,6 @@
#include <acpi/acpi.h>
#include <acpi/acdispat.h>
-#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
#include <acpi/acinterp.h>
@@ -52,11 +51,11 @@ ACPI_MODULE_NAME("dsmthdat")
/* Local prototypes */
static void
-acpi_ds_method_data_delete_value(u16 opcode,
+acpi_ds_method_data_delete_value(u8 type,
u32 index, struct acpi_walk_state *walk_state);
static acpi_status
-acpi_ds_method_data_set_value(u16 opcode,
+acpi_ds_method_data_set_value(u8 type,
u32 index,
union acpi_operand_object *object,
struct acpi_walk_state *walk_state);
@@ -216,7 +215,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
* Store the argument in the method/walk descriptor.
* Do not copy the arg in order to implement call by reference
*/
- status = acpi_ds_method_data_set_value(AML_ARG_OP, index,
+ status = acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index,
params[index],
walk_state);
if (ACPI_FAILURE(status)) {
@@ -234,7 +233,8 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
*
* FUNCTION: acpi_ds_method_data_get_node
*
- * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
* Index - Which Local or Arg whose type to get
* walk_state - Current walk state object
* Node - Where the node is returned.
@@ -246,7 +246,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
******************************************************************************/
acpi_status
-acpi_ds_method_data_get_node(u16 opcode,
+acpi_ds_method_data_get_node(u8 type,
u32 index,
struct acpi_walk_state *walk_state,
struct acpi_namespace_node **node)
@@ -256,8 +256,8 @@ acpi_ds_method_data_get_node(u16 opcode,
/*
* Method Locals and Arguments are supported
*/
- switch (opcode) {
- case AML_LOCAL_OP:
+ switch (type) {
+ case ACPI_REFCLASS_LOCAL:
if (index > ACPI_METHOD_MAX_LOCAL) {
ACPI_ERROR((AE_INFO,
@@ -271,7 +271,7 @@ acpi_ds_method_data_get_node(u16 opcode,
*node = &walk_state->local_variables[index];
break;
- case AML_ARG_OP:
+ case ACPI_REFCLASS_ARG:
if (index > ACPI_METHOD_MAX_ARG) {
ACPI_ERROR((AE_INFO,
@@ -286,8 +286,8 @@ acpi_ds_method_data_get_node(u16 opcode,
break;
default:
- ACPI_ERROR((AE_INFO, "Opcode %d is invalid", opcode));
- return_ACPI_STATUS(AE_AML_BAD_OPCODE);
+ ACPI_ERROR((AE_INFO, "Type %d is invalid", type));
+ return_ACPI_STATUS(AE_TYPE);
}
return_ACPI_STATUS(AE_OK);
@@ -297,7 +297,8 @@ acpi_ds_method_data_get_node(u16 opcode,
*
* FUNCTION: acpi_ds_method_data_set_value
*
- * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
* Index - Which Local or Arg to get
* Object - Object to be inserted into the stack entry
* walk_state - Current walk state object
@@ -310,7 +311,7 @@ acpi_ds_method_data_get_node(u16 opcode,
******************************************************************************/
static acpi_status
-acpi_ds_method_data_set_value(u16 opcode,
+acpi_ds_method_data_set_value(u8 type,
u32 index,
union acpi_operand_object *object,
struct acpi_walk_state *walk_state)
@@ -321,13 +322,13 @@ acpi_ds_method_data_set_value(u16 opcode,
ACPI_FUNCTION_TRACE(ds_method_data_set_value);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "NewObj %p Opcode %X, Refs=%d [%s]\n", object,
- opcode, object->common.reference_count,
+ "NewObj %p Type %2.2X, Refs=%d [%s]\n", object,
+ type, object->common.reference_count,
acpi_ut_get_type_name(object->common.type)));
/* Get the namespace node for the arg/local */
- status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
+ status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -350,7 +351,8 @@ acpi_ds_method_data_set_value(u16 opcode,
*
* FUNCTION: acpi_ds_method_data_get_value
*
- * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
* Index - Which local_var or argument to get
* walk_state - Current walk state object
* dest_desc - Where Arg or Local value is returned
@@ -363,7 +365,7 @@ acpi_ds_method_data_set_value(u16 opcode,
******************************************************************************/
acpi_status
-acpi_ds_method_data_get_value(u16 opcode,
+acpi_ds_method_data_get_value(u8 type,
u32 index,
struct acpi_walk_state *walk_state,
union acpi_operand_object **dest_desc)
@@ -383,7 +385,7 @@ acpi_ds_method_data_get_value(u16 opcode,
/* Get the namespace node for the arg/local */
- status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
+ status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -419,8 +421,8 @@ acpi_ds_method_data_get_value(u16 opcode,
/* Otherwise, return the error */
else
- switch (opcode) {
- case AML_ARG_OP:
+ switch (type) {
+ case ACPI_REFCLASS_ARG:
ACPI_ERROR((AE_INFO,
"Uninitialized Arg[%d] at node %p",
@@ -428,7 +430,7 @@ acpi_ds_method_data_get_value(u16 opcode,
return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);
- case AML_LOCAL_OP:
+ case ACPI_REFCLASS_LOCAL:
ACPI_ERROR((AE_INFO,
"Uninitialized Local[%d] at node %p",
@@ -437,9 +439,10 @@ acpi_ds_method_data_get_value(u16 opcode,
return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);
default:
+
ACPI_ERROR((AE_INFO,
"Not a Arg/Local opcode: %X",
- opcode));
+ type));
return_ACPI_STATUS(AE_AML_INTERNAL);
}
}
@@ -458,7 +461,8 @@ acpi_ds_method_data_get_value(u16 opcode,
*
* FUNCTION: acpi_ds_method_data_delete_value
*
- * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
* Index - Which local_var or argument to delete
* walk_state - Current walk state object
*
@@ -470,7 +474,7 @@ acpi_ds_method_data_get_value(u16 opcode,
******************************************************************************/
static void
-acpi_ds_method_data_delete_value(u16 opcode,
+acpi_ds_method_data_delete_value(u8 type,
u32 index, struct acpi_walk_state *walk_state)
{
acpi_status status;
@@ -481,7 +485,7 @@ acpi_ds_method_data_delete_value(u16 opcode,
/* Get the namespace node for the arg/local */
- status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
+ status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
if (ACPI_FAILURE(status)) {
return_VOID;
}
@@ -514,7 +518,8 @@ acpi_ds_method_data_delete_value(u16 opcode,
*
* FUNCTION: acpi_ds_store_object_to_local
*
- * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
* Index - Which Local or Arg to set
* obj_desc - Value to be stored
* walk_state - Current walk state
@@ -528,7 +533,7 @@ acpi_ds_method_data_delete_value(u16 opcode,
******************************************************************************/
acpi_status
-acpi_ds_store_object_to_local(u16 opcode,
+acpi_ds_store_object_to_local(u8 type,
u32 index,
union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state)
@@ -539,8 +544,8 @@ acpi_ds_store_object_to_local(u16 opcode,
union acpi_operand_object *new_obj_desc;
ACPI_FUNCTION_TRACE(ds_store_object_to_local);
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n",
- opcode, index, obj_desc));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%d Obj=%p\n",
+ type, index, obj_desc));
/* Parameter validation */
@@ -550,7 +555,7 @@ acpi_ds_store_object_to_local(u16 opcode,
/* Get the namespace node for the arg/local */
- status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
+ status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -602,7 +607,7 @@ acpi_ds_store_object_to_local(u16 opcode,
*
* Weird, but true.
*/
- if (opcode == AML_ARG_OP) {
+ if (type == ACPI_REFCLASS_ARG) {
/*
* If we have a valid reference object that came from ref_of(),
* do the indirect store
@@ -611,8 +616,8 @@ acpi_ds_store_object_to_local(u16 opcode,
ACPI_DESC_TYPE_OPERAND)
&& (current_obj_desc->common.type ==
ACPI_TYPE_LOCAL_REFERENCE)
- && (current_obj_desc->reference.opcode ==
- AML_REF_OF_OP)) {
+ && (current_obj_desc->reference.class ==
+ ACPI_REFCLASS_REFOF)) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Arg (%p) is an ObjRef(Node), storing in node %p\n",
new_obj_desc,
@@ -640,11 +645,9 @@ acpi_ds_store_object_to_local(u16 opcode,
}
}
- /*
- * Delete the existing object
- * before storing the new one
- */
- acpi_ds_method_data_delete_value(opcode, index, walk_state);
+ /* Delete the existing object before storing the new one */
+
+ acpi_ds_method_data_delete_value(type, index, walk_state);
}
/*
@@ -653,7 +656,7 @@ acpi_ds_store_object_to_local(u16 opcode,
* (increments the object reference count by one)
*/
status =
- acpi_ds_method_data_set_value(opcode, index, new_obj_desc,
+ acpi_ds_method_data_set_value(type, index, new_obj_desc,
walk_state);
/* Remove local reference if we copied the object above */
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 0f280589921..4f08e599d07 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -731,54 +731,70 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
switch (op_info->type) {
case AML_TYPE_LOCAL_VARIABLE:
- /* Split the opcode into a base opcode + offset */
+ /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */
- obj_desc->reference.opcode = AML_LOCAL_OP;
- obj_desc->reference.offset = opcode - AML_LOCAL_OP;
+ obj_desc->reference.value = opcode - AML_LOCAL_OP;
+ obj_desc->reference.class = ACPI_REFCLASS_LOCAL;
#ifndef ACPI_NO_METHOD_EXECUTION
- status = acpi_ds_method_data_get_node(AML_LOCAL_OP,
- obj_desc->
- reference.offset,
- walk_state,
- (struct
- acpi_namespace_node
- **)&obj_desc->
- reference.object);
+ status =
+ acpi_ds_method_data_get_node(ACPI_REFCLASS_LOCAL,
+ obj_desc->reference.
+ value, walk_state,
+ ACPI_CAST_INDIRECT_PTR
+ (struct
+ acpi_namespace_node,
+ &obj_desc->reference.
+ object));
#endif
break;
case AML_TYPE_METHOD_ARGUMENT:
- /* Split the opcode into a base opcode + offset */
+ /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */
- obj_desc->reference.opcode = AML_ARG_OP;
- obj_desc->reference.offset = opcode - AML_ARG_OP;
+ obj_desc->reference.value = opcode - AML_ARG_OP;
+ obj_desc->reference.class = ACPI_REFCLASS_ARG;
#ifndef ACPI_NO_METHOD_EXECUTION
- status = acpi_ds_method_data_get_node(AML_ARG_OP,
+ status = acpi_ds_method_data_get_node(ACPI_REFCLASS_ARG,
obj_desc->
- reference.offset,
+ reference.value,
walk_state,
+ ACPI_CAST_INDIRECT_PTR
(struct
- acpi_namespace_node
- **)&obj_desc->
- reference.object);
+ acpi_namespace_node,
+ &obj_desc->
+ reference.
+ object));
#endif
break;
- default: /* Other literals, etc.. */
+ default: /* Object name or Debug object */
- if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ switch (op->common.aml_opcode) {
+ case AML_INT_NAMEPATH_OP:
/* Node was saved in Op */
obj_desc->reference.node = op->common.node;
obj_desc->reference.object =
op->common.node->object;
- }
+ obj_desc->reference.class = ACPI_REFCLASS_NAME;
+ break;
+
+ case AML_DEBUG_OP:
- obj_desc->reference.opcode = opcode;
+ obj_desc->reference.class = ACPI_REFCLASS_DEBUG;
+ break;
+
+ default:
+
+ ACPI_ERROR((AE_INFO,
+ "Unimplemented reference type for AML opcode: %4.4X",
+ opcode));
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
break;
}
break;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index 6a81c4400ed..69fae5905bb 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -1330,7 +1330,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
(walk_state->results->results.obj_desc[0]) ==
ACPI_TYPE_LOCAL_REFERENCE)
&& ((walk_state->results->results.obj_desc[0])->
- reference.opcode != AML_INDEX_OP)) {
+ reference.class != ACPI_REFCLASS_INDEX)) {
status =
acpi_ex_resolve_to_value(&walk_state->
results->results.
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index b5072fa9c92..396fe12078c 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -166,6 +166,10 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
status = AE_CTRL_FALSE;
}
+ /* Predicate can be used for an implicit return value */
+
+ (void)acpi_ds_do_implicit_return(local_obj_desc, walk_state, TRUE);
+
cleanup:
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n",
@@ -429,10 +433,10 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
ACPI_TYPE_LOCAL_REFERENCE)
&& (walk_state->operands[1]->common.type ==
ACPI_TYPE_LOCAL_REFERENCE)
- && (walk_state->operands[0]->reference.opcode ==
- walk_state->operands[1]->reference.opcode)
- && (walk_state->operands[0]->reference.offset ==
- walk_state->operands[1]->reference.offset)) {
+ && (walk_state->operands[0]->reference.class ==
+ walk_state->operands[1]->reference.class)
+ && (walk_state->operands[0]->reference.value ==
+ walk_state->operands[1]->reference.value)) {
status = AE_OK;
} else {
ACPI_EXCEPTION((AE_INFO, status,
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 7d2edf143f1..5b30b8d91d7 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
" before undocking");
static struct atomic_notifier_head dock_notifier_list;
-static struct platform_device *dock_device;
static char dock_device_name[] = "dock";
static const struct acpi_device_id dock_device_ids[] = {
@@ -65,23 +64,29 @@ struct dock_station {
struct mutex hp_lock;
struct list_head dependent_devices;
struct list_head hotplug_devices;
+
+ struct list_head sibiling;
+ struct platform_device *dock_device;
};
+static LIST_HEAD(dock_stations);
+static int dock_station_count;
struct dock_dependent_device {
struct list_head list;
struct list_head hotplug_list;
acpi_handle handle;
- acpi_notify_handler handler;
+ struct acpi_dock_ops *ops;
void *context;
};
#define DOCK_DOCKING 0x00000001
#define DOCK_UNDOCKING 0x00000002
+#define DOCK_IS_DOCK 0x00000010
+#define DOCK_IS_ATA 0x00000020
+#define DOCK_IS_BAT 0x00000040
#define DOCK_EVENT 3
#define UNDOCK_EVENT 2
-static struct dock_station *dock_station;
-
/*****************************************************************************
* Dock Dependent device functions *
*****************************************************************************/
@@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle)
return 1;
}
+static int is_ejectable(acpi_handle handle)
+{
+ acpi_status status;
+ acpi_handle tmp;
+
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
+ if (ACPI_FAILURE(status))
+ return 0;
+ return 1;
+}
+
+static int is_ata(acpi_handle handle)
+{
+ acpi_handle tmp;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+ return 1;
+
+ return 0;
+}
+
+static int is_battery(acpi_handle handle)
+{
+ struct acpi_device_info *info;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ int ret = 1;
+
+ if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer)))
+ return 0;
+ info = buffer.pointer;
+ if (!(info->valid & ACPI_VALID_HID))
+ ret = 0;
+ else
+ ret = !strcmp("PNP0C0A", info->hardware_id.value);
+
+ kfree(buffer.pointer);
+ return ret;
+}
+
+static int is_ejectable_bay(acpi_handle handle)
+{
+ acpi_handle phandle;
+ if (!is_ejectable(handle))
+ return 0;
+ if (is_battery(handle) || is_ata(handle))
+ return 1;
+ if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
+ return 1;
+ return 0;
+}
+
/**
* is_dock_device - see if a device is on a dock station
* @handle: acpi handle of the device
@@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle)
*/
int is_dock_device(acpi_handle handle)
{
- if (!dock_station)
+ struct dock_station *dock_station;
+
+ if (!dock_station_count)
return 0;
- if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
+ if (is_dock(handle))
return 1;
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ if (find_dock_dependent_device(dock_station, handle))
+ return 1;
+ }
return 0;
}
@@ -229,7 +294,7 @@ EXPORT_SYMBOL_GPL(is_dock_device);
*/
static int dock_present(struct dock_station *ds)
{
- unsigned long sta;
+ unsigned long long sta;
acpi_status status;
if (ds) {
@@ -320,8 +385,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
* First call driver specific hotplug functions
*/
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
- if (dd->handler)
- dd->handler(dd->handle, event, dd->context);
+ if (dd->ops && dd->ops->handler)
+ dd->ops->handler(dd->handle, event, dd->context);
}
/*
@@ -341,9 +406,10 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
static void dock_event(struct dock_station *ds, u32 event, int num)
{
- struct device *dev = &dock_device->dev;
+ struct device *dev = &ds->dock_device->dev;
char event_string[13];
char *envp[] = { event_string, NULL };
+ struct dock_dependent_device *dd;
if (num == UNDOCK_EVENT)
sprintf(event_string, "EVENT=undock");
@@ -354,7 +420,14 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
* Indicate that the status of the dock station has
* changed.
*/
- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+ if (num == DOCK_EVENT)
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+
+ list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
+ if (dd->ops && dd->ops->uevent)
+ dd->ops->uevent(dd->handle, event, dd->context);
+ if (num != DOCK_EVENT)
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
}
/**
@@ -414,9 +487,10 @@ static void handle_dock(struct dock_station *ds, int dock)
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = dock;
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
- if (ACPI_FAILURE(status))
- printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
- (char *)name_buffer.pointer);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+ ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute"
+ " _DCK\n", (char *)name_buffer.pointer));
+
kfree(buffer.pointer);
kfree(name_buffer.pointer);
}
@@ -452,6 +526,25 @@ static inline void complete_undock(struct dock_station *ds)
ds->flags &= ~(DOCK_UNDOCKING);
}
+static void dock_lock(struct dock_station *ds, int lock)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status;
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = !!lock;
+ status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ if (lock)
+ printk(KERN_WARNING PREFIX "Locking device failed\n");
+ else
+ printk(KERN_WARNING PREFIX "Unlocking device failed\n");
+ }
+}
+
/**
* dock_in_progress - see if we are in the middle of handling a dock event
* @ds: the dock station
@@ -479,7 +572,7 @@ static int dock_in_progress(struct dock_station *ds)
*/
int register_dock_notifier(struct notifier_block *nb)
{
- if (!dock_station)
+ if (!dock_station_count)
return -ENODEV;
return atomic_notifier_chain_register(&dock_notifier_list, nb);
@@ -493,7 +586,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier);
*/
void unregister_dock_notifier(struct notifier_block *nb)
{
- if (!dock_station)
+ if (!dock_station_count)
return;
atomic_notifier_chain_unregister(&dock_notifier_list, nb);
@@ -504,7 +597,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
/**
* register_hotplug_dock_device - register a hotplug function
* @handle: the handle of the device
- * @handler: the acpi_notifier_handler to call after docking
+ * @ops: handlers to call after docking
* @context: device specific data
*
* If a driver would like to perform a hotplug operation after a dock
@@ -512,27 +605,36 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
* the dock driver after _DCK is executed.
*/
int
-register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
+register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
void *context)
{
struct dock_dependent_device *dd;
+ struct dock_station *dock_station;
+ int ret = -EINVAL;
- if (!dock_station)
+ if (!dock_station_count)
return -ENODEV;
/*
* make sure this handle is for a device dependent on the dock,
* this would include the dock station itself
*/
- dd = find_dock_dependent_device(dock_station, handle);
- if (dd) {
- dd->handler = handler;
- dd->context = context;
- dock_add_hotplug_device(dock_station, dd);
- return 0;
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ /*
+ * An ATA bay can be in a dock and itself can be ejected
+ * seperately, so there are two 'dock stations' which need the
+ * ops
+ */
+ dd = find_dock_dependent_device(dock_station, handle);
+ if (dd) {
+ dd->ops = ops;
+ dd->context = context;
+ dock_add_hotplug_device(dock_station, dd);
+ ret = 0;
+ }
}
- return -EINVAL;
+ return ret;
}
EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
@@ -544,13 +646,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
void unregister_hotplug_dock_device(acpi_handle handle)
{
struct dock_dependent_device *dd;
+ struct dock_station *dock_station;
- if (!dock_station)
+ if (!dock_station_count)
return;
- dd = find_dock_dependent_device(dock_station, handle);
- if (dd)
- dock_del_hotplug_device(dock_station, dd);
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ dd = find_dock_dependent_device(dock_station, handle);
+ if (dd)
+ dock_del_hotplug_device(dock_station, dd);
+ }
}
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
@@ -575,13 +680,9 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
*/
dock_event(ds, event, UNDOCK_EVENT);
- if (!dock_present(ds)) {
- complete_undock(ds);
- return -ENODEV;
- }
-
hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
undock(ds);
+ dock_lock(ds, 0);
eject_dock(ds);
if (dock_present(ds)) {
printk(KERN_ERR PREFIX "Unable to undock!\n");
@@ -604,14 +705,36 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
static void dock_notify(acpi_handle handle, u32 event, void *data)
{
struct dock_station *ds = data;
+ struct acpi_device *tmp;
+ int surprise_removal = 0;
+
+ /*
+ * According to acpi spec 3.0a, if a DEVICE_CHECK notification
+ * is sent and _DCK is present, it is assumed to mean an undock
+ * request.
+ */
+ if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
+ event = ACPI_NOTIFY_EJECT_REQUEST;
+ /*
+ * dock station: BUS_CHECK - docked or surprise removal
+ * DEVICE_CHECK - undocked
+ * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
+ *
+ * To simplify event handling, dock dependent device handler always
+ * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
+ * ACPI_NOTIFY_EJECT_REQUEST for removal
+ */
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
- if (!dock_in_progress(ds) && dock_present(ds)) {
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
+ &tmp)) {
begin_dock(ds);
dock(ds);
if (!dock_present(ds)) {
printk(KERN_ERR PREFIX "Unable to dock!\n");
+ complete_dock(ds);
break;
}
atomic_notifier_call_chain(&dock_notifier_list,
@@ -619,20 +742,19 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
hotplug_dock_devices(ds, event);
complete_dock(ds);
dock_event(ds, event, DOCK_EVENT);
+ dock_lock(ds, 1);
+ break;
}
- break;
- case ACPI_NOTIFY_DEVICE_CHECK:
- /*
- * According to acpi spec 3.0a, if a DEVICE_CHECK notification
- * is sent and _DCK is present, it is assumed to mean an
- * undock request. This notify routine will only be called
- * for objects defining _DCK, so we will fall through to eject
- * request here. However, we will pass an eject request through
- * to the driver who wish to hotplug.
- */
+ if (dock_present(ds) || dock_in_progress(ds))
+ break;
+ /* This is a surprise removal */
+ surprise_removal = 1;
+ event = ACPI_NOTIFY_EJECT_REQUEST;
+ /* Fall back */
case ACPI_NOTIFY_EJECT_REQUEST:
begin_undock(ds);
- if (immediate_undock)
+ if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
+ || surprise_removal)
handle_eject_request(ds, event);
else
dock_event(ds, event, UNDOCK_EVENT);
@@ -642,6 +764,51 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
}
}
+struct dock_data {
+ acpi_handle handle;
+ unsigned long event;
+ struct dock_station *ds;
+};
+
+static void acpi_dock_deferred_cb(void *context)
+{
+ struct dock_data *data = (struct dock_data *)context;
+
+ dock_notify(data->handle, data->event, data->ds);
+ kfree(data);
+}
+
+static int acpi_dock_notifier_call(struct notifier_block *this,
+ unsigned long event, void *data)
+{
+ struct dock_station *dock_station;
+ acpi_handle handle = (acpi_handle)data;
+
+ if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
+ && event != ACPI_NOTIFY_EJECT_REQUEST)
+ return 0;
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ if (dock_station->handle == handle) {
+ struct dock_data *dock_data;
+
+ dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL);
+ if (!dock_data)
+ return 0;
+ dock_data->handle = handle;
+ dock_data->event = event;
+ dock_data->ds = dock_station;
+ acpi_os_hotplug_execute(acpi_dock_deferred_cb,
+ dock_data);
+ return 0 ;
+ }
+ }
+ return 0;
+}
+
+static struct notifier_block dock_acpi_notifier = {
+ .notifier_call = acpi_dock_notifier_call,
+};
+
/**
* find_dock_devices - find devices on the dock station
* @handle: the handle of the device we are examining
@@ -688,6 +855,8 @@ fdd_out:
static ssize_t show_docked(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ struct dock_station *dock_station = *((struct dock_station **)
+ dev->platform_data);
return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
}
@@ -699,6 +868,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
static ssize_t show_flags(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ struct dock_station *dock_station = *((struct dock_station **)
+ dev->platform_data);
return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
}
@@ -711,6 +882,8 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
+ struct dock_station *dock_station = *((struct dock_station **)
+ dev->platform_data);
if (!count)
return -EINVAL;
@@ -727,16 +900,38 @@ static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
static ssize_t show_dock_uid(struct device *dev,
struct device_attribute *attr, char *buf)
{
- unsigned long lbuf;
+ unsigned long long lbuf;
+ struct dock_station *dock_station = *((struct dock_station **)
+ dev->platform_data);
acpi_status status = acpi_evaluate_integer(dock_station->handle,
"_UID", NULL, &lbuf);
if (ACPI_FAILURE(status))
return 0;
- return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
+ return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf);
}
static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
+static ssize_t show_dock_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dock_station *dock_station = *((struct dock_station **)
+ dev->platform_data);
+ char *type;
+
+ if (dock_station->flags & DOCK_IS_DOCK)
+ type = "dock_station";
+ else if (dock_station->flags & DOCK_IS_ATA)
+ type = "ata_bay";
+ else if (dock_station->flags & DOCK_IS_BAT)
+ type = "battery_bay";
+ else
+ type = "unknown";
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", type);
+}
+static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
+
/**
* dock_add - add a new dock station
* @handle: the dock station handle
@@ -747,8 +942,9 @@ static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
static int dock_add(acpi_handle handle)
{
int ret;
- acpi_status status;
struct dock_dependent_device *dd;
+ struct dock_station *dock_station;
+ struct platform_device *dock_device;
/* allocate & initialize the dock_station private data */
dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
@@ -758,22 +954,34 @@ static int dock_add(acpi_handle handle)
dock_station->last_dock_time = jiffies - HZ;
INIT_LIST_HEAD(&dock_station->dependent_devices);
INIT_LIST_HEAD(&dock_station->hotplug_devices);
+ INIT_LIST_HEAD(&dock_station->sibiling);
spin_lock_init(&dock_station->dd_lock);
mutex_init(&dock_station->hp_lock);
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
/* initialize platform device stuff */
- dock_device =
- platform_device_register_simple(dock_device_name, 0, NULL, 0);
+ dock_station->dock_device =
+ platform_device_register_simple(dock_device_name,
+ dock_station_count, NULL, 0);
+ dock_device = dock_station->dock_device;
if (IS_ERR(dock_device)) {
kfree(dock_station);
dock_station = NULL;
return PTR_ERR(dock_device);
}
+ platform_device_add_data(dock_device, &dock_station,
+ sizeof(struct dock_station *));
/* we want the dock device to send uevents */
dock_device->dev.uevent_suppress = 0;
+ if (is_dock(handle))
+ dock_station->flags |= DOCK_IS_DOCK;
+ if (is_ata(handle))
+ dock_station->flags |= DOCK_IS_ATA;
+ if (is_battery(handle))
+ dock_station->flags |= DOCK_IS_BAT;
+
ret = device_create_file(&dock_device->dev, &dev_attr_docked);
if (ret) {
printk("Error %d adding sysfs file\n", ret);
@@ -812,6 +1020,9 @@ static int dock_add(acpi_handle handle)
dock_station = NULL;
return ret;
}
+ ret = device_create_file(&dock_device->dev, &dev_attr_type);
+ if (ret)
+ printk(KERN_ERR"Error %d adding sysfs file\n", ret);
/* Find dependent devices */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
@@ -828,24 +1039,12 @@ static int dock_add(acpi_handle handle)
}
add_dock_dependent_device(dock_station, dd);
- /* register for dock events */
- status = acpi_install_notify_handler(dock_station->handle,
- ACPI_SYSTEM_NOTIFY,
- dock_notify, dock_station);
-
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Error installing notify handler\n");
- ret = -ENODEV;
- goto dock_add_err;
- }
-
- printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION);
-
+ dock_station_count++;
+ list_add(&dock_station->sibiling, &dock_stations);
return 0;
-dock_add_err:
- kfree(dd);
dock_add_err_unregister:
+ device_remove_file(&dock_device->dev, &dev_attr_type);
device_remove_file(&dock_device->dev, &dev_attr_docked);
device_remove_file(&dock_device->dev, &dev_attr_undock);
device_remove_file(&dock_device->dev, &dev_attr_uid);
@@ -859,12 +1058,12 @@ dock_add_err_unregister:
/**
* dock_remove - free up resources related to the dock station
*/
-static int dock_remove(void)
+static int dock_remove(struct dock_station *dock_station)
{
struct dock_dependent_device *dd, *tmp;
- acpi_status status;
+ struct platform_device *dock_device = dock_station->dock_device;
- if (!dock_station)
+ if (!dock_station_count)
return 0;
/* remove dependent devices */
@@ -872,14 +1071,8 @@ static int dock_remove(void)
list)
kfree(dd);
- /* remove dock notify handler */
- status = acpi_remove_notify_handler(dock_station->handle,
- ACPI_SYSTEM_NOTIFY,
- dock_notify);
- if (ACPI_FAILURE(status))
- printk(KERN_ERR "Error removing notify handler\n");
-
/* cleanup sysfs */
+ device_remove_file(&dock_device->dev, &dev_attr_type);
device_remove_file(&dock_device->dev, &dev_attr_docked);
device_remove_file(&dock_device->dev, &dev_attr_undock);
device_remove_file(&dock_device->dev, &dev_attr_uid);
@@ -904,41 +1097,60 @@ static int dock_remove(void)
static acpi_status
find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
{
- int *count = context;
acpi_status status = AE_OK;
if (is_dock(handle)) {
if (dock_add(handle) >= 0) {
- (*count)++;
status = AE_CTRL_TERMINATE;
}
}
return status;
}
-static int __init dock_init(void)
+static acpi_status
+find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
{
- int num = 0;
-
- dock_station = NULL;
+ /* If bay is a dock, it's already handled */
+ if (is_ejectable_bay(handle) && !is_dock(handle))
+ dock_add(handle);
+ return AE_OK;
+}
+static int __init dock_init(void)
+{
if (acpi_disabled)
return 0;
/* look for a dock station */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, find_dock, &num, NULL);
+ ACPI_UINT32_MAX, find_dock, NULL, NULL);
- if (!num)
- printk(KERN_INFO "No dock devices found.\n");
+ /* look for bay */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, find_bay, NULL, NULL);
+ if (!dock_station_count) {
+ printk(KERN_INFO PREFIX "No dock devices found.\n");
+ return 0;
+ }
+ register_acpi_bus_notifier(&dock_acpi_notifier);
+ printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
+ ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
return 0;
}
static void __exit dock_exit(void)
{
- dock_remove();
+ struct dock_station *dock_station;
+
+ unregister_acpi_bus_notifier(&dock_acpi_notifier);
+ list_for_each_entry(dock_station, &dock_stations, sibiling)
+ dock_remove(dock_station);
}
-postcore_initcall(dock_init);
+/*
+ * Must be called before drivers of devices in dock, otherwise we can't know
+ * which devices are in a dock
+ */
+subsys_initcall(dock_init);
module_exit(dock_exit);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 13593f9f219..ef42316f89f 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1,7 +1,7 @@
/*
- * ec.c - ACPI Embedded Controller Driver (v2.0)
+ * ec.c - ACPI Embedded Controller Driver (v2.1)
*
- * Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
+ * Copyright (C) 2006-2008 Alexey Starikovskiy <astarikovskiy@suse.de>
* Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
@@ -26,7 +26,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-/* Uncomment next line to get verbose print outs*/
+/* Uncomment next line to get verbose printout */
/* #define DEBUG */
#include <linux/kernel.h>
@@ -38,6 +38,7 @@
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/list.h>
+#include <linux/spinlock.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -65,22 +66,21 @@ enum ec_command {
ACPI_EC_COMMAND_QUERY = 0x84,
};
-/* EC events */
-enum ec_event {
- ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
- ACPI_EC_EVENT_IBF_0, /* Input buffer empty */
-};
-
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */
+#define ACPI_EC_STORM_THRESHOLD 20 /* number of false interrupts
+ per one transaction */
+
enum {
- EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
EC_FLAGS_QUERY_PENDING, /* Query is pending */
- EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */
+ EC_FLAGS_GPE_MODE, /* Expect GPE to be sent
+ * for status change */
EC_FLAGS_NO_GPE, /* Don't use GPE mode */
- EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */
+ EC_FLAGS_GPE_STORM, /* GPE storm detected */
+ EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and
+ * OpReg are installed */
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -95,6 +95,15 @@ struct acpi_ec_query_handler {
u8 query_bit;
};
+struct transaction {
+ const u8 *wdata;
+ u8 *rdata;
+ unsigned short irq_count;
+ u8 command;
+ u8 wlen;
+ u8 rlen;
+};
+
static struct acpi_ec {
acpi_handle handle;
unsigned long gpe;
@@ -105,9 +114,8 @@ static struct acpi_ec {
struct mutex lock;
wait_queue_head_t wait;
struct list_head list;
- struct delayed_work work;
- atomic_t irq_count;
- u8 handlers_installed;
+ struct transaction *curr;
+ spinlock_t curr_lock;
} *boot_ec, *first_ec;
/*
@@ -150,7 +158,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
{
u8 x = inb(ec->data_addr);
pr_debug(PREFIX "---> data = 0x%2.2x\n", x);
- return inb(ec->data_addr);
+ return x;
}
static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
@@ -165,158 +173,172 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
outb(data, ec->data_addr);
}
-static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
+static int ec_transaction_done(struct acpi_ec *ec)
{
- if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags))
- return 0;
- if (event == ACPI_EC_EVENT_OBF_1) {
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
- return 1;
- } else if (event == ACPI_EC_EVENT_IBF_0) {
- if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF))
- return 1;
- }
-
- return 0;
+ unsigned long flags;
+ int ret = 0;
+ spin_lock_irqsave(&ec->curr_lock, flags);
+ if (!ec->curr || (!ec->curr->wlen && !ec->curr->rlen))
+ ret = 1;
+ spin_unlock_irqrestore(&ec->curr_lock, flags);
+ return ret;
}
-static void ec_schedule_ec_poll(struct acpi_ec *ec)
+static void gpe_transaction(struct acpi_ec *ec, u8 status)
{
- if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags))
- schedule_delayed_work(&ec->work,
- msecs_to_jiffies(ACPI_EC_DELAY));
+ unsigned long flags;
+ spin_lock_irqsave(&ec->curr_lock, flags);
+ if (!ec->curr)
+ goto unlock;
+ if (ec->curr->wlen > 0) {
+ if ((status & ACPI_EC_FLAG_IBF) == 0) {
+ acpi_ec_write_data(ec, *(ec->curr->wdata++));
+ --ec->curr->wlen;
+ } else
+ /* false interrupt, state didn't change */
+ ++ec->curr->irq_count;
+
+ } else if (ec->curr->rlen > 0) {
+ if ((status & ACPI_EC_FLAG_OBF) == 1) {
+ *(ec->curr->rdata++) = acpi_ec_read_data(ec);
+ --ec->curr->rlen;
+ } else
+ /* false interrupt, state didn't change */
+ ++ec->curr->irq_count;
+ }
+unlock:
+ spin_unlock_irqrestore(&ec->curr_lock, flags);
}
-static void ec_switch_to_poll_mode(struct acpi_ec *ec)
+static int acpi_ec_wait(struct acpi_ec *ec)
{
+ if (wait_event_timeout(ec->wait, ec_transaction_done(ec),
+ msecs_to_jiffies(ACPI_EC_DELAY)))
+ return 0;
+ /* missing GPEs, switch back to poll mode */
+ if (printk_ratelimit())
+ pr_info(PREFIX "missing confirmations, "
+ "switch off interrupt mode.\n");
set_bit(EC_FLAGS_NO_GPE, &ec->flags);
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
- acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
- set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
+ return 1;
}
-static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
+static void acpi_ec_gpe_query(void *ec_cxt);
+
+static int ec_check_sci(struct acpi_ec *ec, u8 state)
{
- atomic_set(&ec->irq_count, 0);
- if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
- likely(!force_poll)) {
- if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
- msecs_to_jiffies(ACPI_EC_DELAY)))
- return 0;
- clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
- if (acpi_ec_check_status(ec, event)) {
- /* missing GPEs, switch back to poll mode */
- if (printk_ratelimit())
- pr_info(PREFIX "missing confirmations, "
- "switch off interrupt mode.\n");
- ec_switch_to_poll_mode(ec);
- ec_schedule_ec_poll(ec);
- return 0;
- }
- } else {
- unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
- clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
- while (time_before(jiffies, delay)) {
- if (acpi_ec_check_status(ec, event))
- return 0;
- msleep(1);
- }
- if (acpi_ec_check_status(ec,event))
+ if (state & ACPI_EC_FLAG_SCI) {
+ if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
+ return acpi_os_execute(OSL_EC_BURST_HANDLER,
+ acpi_ec_gpe_query, ec);
+ }
+ return 0;
+}
+
+static int ec_poll(struct acpi_ec *ec)
+{
+ unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
+ msleep(1);
+ while (time_before(jiffies, delay)) {
+ gpe_transaction(ec, acpi_ec_read_status(ec));
+ msleep(1);
+ if (ec_transaction_done(ec))
return 0;
}
- pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
- acpi_ec_read_status(ec),
- (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\"");
return -ETIME;
}
-static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
- const u8 * wdata, unsigned wdata_len,
- u8 * rdata, unsigned rdata_len,
+static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
+ struct transaction *t,
int force_poll)
{
- int result = 0;
- set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
+ unsigned long tmp;
+ int ret = 0;
pr_debug(PREFIX "transaction start\n");
- acpi_ec_write_cmd(ec, command);
- for (; wdata_len > 0; --wdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
- if (result) {
- pr_err(PREFIX
- "write_cmd timeout, command = %d\n", command);
- goto end;
- }
- set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
- acpi_ec_write_data(ec, *(wdata++));
+ /* disable GPE during transaction if storm is detected */
+ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+ clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
}
-
- if (!rdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
- if (result) {
- pr_err(PREFIX
- "finish-write timeout, command = %d\n", command);
- goto end;
- }
- } else if (command == ACPI_EC_COMMAND_QUERY)
+ /* start transaction */
+ spin_lock_irqsave(&ec->curr_lock, tmp);
+ /* following two actions should be kept atomic */
+ t->irq_count = 0;
+ ec->curr = t;
+ acpi_ec_write_cmd(ec, ec->curr->command);
+ if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
-
- for (; rdata_len > 0; --rdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll);
- if (result) {
- pr_err(PREFIX "read timeout, command = %d\n", command);
- goto end;
- }
- /* Don't expect GPE after last read */
- if (rdata_len > 1)
- set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
- *(rdata++) = acpi_ec_read_data(ec);
- }
- end:
+ spin_unlock_irqrestore(&ec->curr_lock, tmp);
+ /* if we selected poll mode or failed in GPE-mode do a poll loop */
+ if (force_poll ||
+ !test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ||
+ acpi_ec_wait(ec))
+ ret = ec_poll(ec);
pr_debug(PREFIX "transaction end\n");
- return result;
+ spin_lock_irqsave(&ec->curr_lock, tmp);
+ ec->curr = NULL;
+ spin_unlock_irqrestore(&ec->curr_lock, tmp);
+ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+ /* check if we received SCI during transaction */
+ ec_check_sci(ec, acpi_ec_read_status(ec));
+ /* it is safe to enable GPE outside of transaction */
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ } else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
+ t->irq_count > ACPI_EC_STORM_THRESHOLD) {
+ pr_debug(PREFIX "GPE storm detected\n");
+ set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
+ }
+ return ret;
+}
+
+static int ec_check_ibf0(struct acpi_ec *ec)
+{
+ u8 status = acpi_ec_read_status(ec);
+ return (status & ACPI_EC_FLAG_IBF) == 0;
}
-static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
- const u8 * wdata, unsigned wdata_len,
- u8 * rdata, unsigned rdata_len,
+static int ec_wait_ibf0(struct acpi_ec *ec)
+{
+ unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
+ /* interrupt wait manually if GPE mode is not active */
+ unsigned long timeout = test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ?
+ msecs_to_jiffies(ACPI_EC_DELAY) : msecs_to_jiffies(1);
+ while (time_before(jiffies, delay))
+ if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), timeout))
+ return 0;
+ return -ETIME;
+}
+
+static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t,
int force_poll)
{
int status;
u32 glk;
-
- if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
+ if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
return -EINVAL;
-
- if (rdata)
- memset(rdata, 0, rdata_len);
-
+ if (t->rdata)
+ memset(t->rdata, 0, t->rlen);
mutex_lock(&ec->lock);
if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status)) {
- mutex_unlock(&ec->lock);
- return -ENODEV;
+ status = -ENODEV;
+ goto unlock;
}
}
-
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
- if (status) {
+ if (ec_wait_ibf0(ec)) {
pr_err(PREFIX "input buffer is not empty, "
"aborting transaction\n");
+ status = -ETIME;
goto end;
}
-
- status = acpi_ec_transaction_unlocked(ec, command,
- wdata, wdata_len,
- rdata, rdata_len,
- force_poll);
-
- end:
-
+ status = acpi_ec_transaction_unlocked(ec, t, force_poll);
+end:
if (ec->global_lock)
acpi_release_global_lock(glk);
+unlock:
mutex_unlock(&ec->lock);
-
return status;
}
@@ -327,21 +349,32 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
int acpi_ec_burst_enable(struct acpi_ec *ec)
{
u8 d;
- return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0);
+ struct transaction t = {.command = ACPI_EC_BURST_ENABLE,
+ .wdata = NULL, .rdata = &d,
+ .wlen = 0, .rlen = 1};
+
+ return acpi_ec_transaction(ec, &t, 0);
}
int acpi_ec_burst_disable(struct acpi_ec *ec)
{
- return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0);
+ struct transaction t = {.command = ACPI_EC_BURST_DISABLE,
+ .wdata = NULL, .rdata = NULL,
+ .wlen = 0, .rlen = 0};
+
+ return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
+ acpi_ec_transaction(ec, &t, 0) : 0;
}
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
{
int result;
u8 d;
+ struct transaction t = {.command = ACPI_EC_COMMAND_READ,
+ .wdata = &address, .rdata = &d,
+ .wlen = 1, .rlen = 1};
- result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
- &address, 1, &d, 1, 0);
+ result = acpi_ec_transaction(ec, &t, 0);
*data = d;
return result;
}
@@ -349,8 +382,11 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
{
u8 wdata[2] = { address, data };
- return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
- wdata, 2, NULL, 0, 0);
+ struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
+ .wdata = wdata, .rdata = NULL,
+ .wlen = 2, .rlen = 0};
+
+ return acpi_ec_transaction(ec, &t, 0);
}
/*
@@ -412,12 +448,13 @@ int ec_transaction(u8 command,
u8 * rdata, unsigned rdata_len,
int force_poll)
{
+ struct transaction t = {.command = command,
+ .wdata = wdata, .rdata = rdata,
+ .wlen = wdata_len, .rlen = rdata_len};
if (!first_ec)
return -ENODEV;
- return acpi_ec_transaction(first_ec, command, wdata,
- wdata_len, rdata, rdata_len,
- force_poll);
+ return acpi_ec_transaction(first_ec, &t, force_poll);
}
EXPORT_SYMBOL(ec_transaction);
@@ -426,7 +463,9 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
{
int result;
u8 d;
-
+ struct transaction t = {.command = ACPI_EC_COMMAND_QUERY,
+ .wdata = NULL, .rdata = &d,
+ .wlen = 0, .rlen = 1};
if (!ec || !data)
return -EINVAL;
@@ -436,7 +475,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
* bit to be cleared (and thus clearing the interrupt source).
*/
- result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0);
+ result = acpi_ec_transaction(ec, &t, 0);
if (result)
return result;
@@ -513,46 +552,26 @@ static void acpi_ec_gpe_query(void *ec_cxt)
static u32 acpi_ec_gpe_handler(void *data)
{
- acpi_status status = AE_OK;
struct acpi_ec *ec = data;
- u8 state = acpi_ec_read_status(ec);
+ u8 status;
pr_debug(PREFIX "~~~> interrupt\n");
- atomic_inc(&ec->irq_count);
- if (atomic_read(&ec->irq_count) > 5) {
- pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
- ec_switch_to_poll_mode(ec);
- goto end;
- }
- clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
- if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
+ status = acpi_ec_read_status(ec);
+
+ gpe_transaction(ec, status);
+ if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0)
wake_up(&ec->wait);
- if (state & ACPI_EC_FLAG_SCI) {
- if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
- status = acpi_os_execute(OSL_EC_BURST_HANDLER,
- acpi_ec_gpe_query, ec);
- } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
- !test_bit(EC_FLAGS_NO_GPE, &ec->flags) &&
- in_interrupt()) {
+ ec_check_sci(ec, status);
+ if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
+ !test_bit(EC_FLAGS_NO_GPE, &ec->flags)) {
/* this is non-query, must be confirmation */
if (printk_ratelimit())
pr_info(PREFIX "non-query interrupt received,"
" switching to interrupt mode\n");
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
- clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
}
-end:
- ec_schedule_ec_poll(ec);
- return ACPI_SUCCESS(status) ?
- ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
-}
-
-static void do_ec_poll(struct work_struct *work)
-{
- struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
- atomic_set(&ec->irq_count, 0);
- (void)acpi_ec_gpe_handler(ec);
+ return ACPI_INTERRUPT_HANDLED;
}
/* --------------------------------------------------------------------------
@@ -696,8 +715,7 @@ static struct acpi_ec *make_acpi_ec(void)
mutex_init(&ec->lock);
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
- INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
- atomic_set(&ec->irq_count, 0);
+ spin_lock_init(&ec->curr_lock);
return ec;
}
@@ -718,6 +736,7 @@ static acpi_status
ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
{
acpi_status status;
+ unsigned long long tmp;
struct acpi_ec *ec = context;
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
@@ -727,31 +746,26 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
- status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
+ status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
if (ACPI_FAILURE(status))
return status;
+ ec->gpe = tmp;
/* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
+ acpi_evaluate_integer(handle, "_GLK", NULL, &tmp);
+ ec->global_lock = tmp;
ec->handle = handle;
return AE_CTRL_TERMINATE;
}
-static void ec_poll_stop(struct acpi_ec *ec)
-{
- clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
- cancel_delayed_work(&ec->work);
-}
-
static void ec_remove_handlers(struct acpi_ec *ec)
{
- ec_poll_stop(ec);
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
pr_err(PREFIX "failed to remove space handler\n");
if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
&acpi_ec_gpe_handler)))
pr_err(PREFIX "failed to remove gpe handler\n");
- ec->handlers_installed = 0;
+ clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
}
static int acpi_ec_add(struct acpi_device *device)
@@ -788,7 +802,7 @@ static int acpi_ec_add(struct acpi_device *device)
if (!first_ec)
first_ec = ec;
- acpi_driver_data(device) = ec;
+ device->driver_data = ec;
acpi_ec_add_fs(device);
pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
ec->gpe, ec->command_addr, ec->data_addr);
@@ -813,7 +827,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
}
mutex_unlock(&ec->lock);
acpi_ec_remove_fs(device);
- acpi_driver_data(device) = NULL;
+ device->driver_data = NULL;
if (ec == first_ec)
first_ec = NULL;
kfree(ec);
@@ -846,27 +860,36 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
static int ec_install_handlers(struct acpi_ec *ec)
{
acpi_status status;
- if (ec->handlers_installed)
+ if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
return 0;
status = acpi_install_gpe_handler(NULL, ec->gpe,
- ACPI_GPE_EDGE_TRIGGERED,
- &acpi_ec_gpe_handler, ec);
+ ACPI_GPE_EDGE_TRIGGERED,
+ &acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status))
return -ENODEV;
-
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
-
status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
NULL, ec);
if (ACPI_FAILURE(status)) {
- acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
- return -ENODEV;
+ if (status == AE_NOT_FOUND) {
+ /*
+ * Maybe OS fails in evaluating the _REG object.
+ * The AE_NOT_FOUND error will be ignored and OS
+ * continue to initialize EC.
+ */
+ printk(KERN_ERR "Fail in evaluating the _REG object"
+ " of EC device. Broken bios is suspected.\n");
+ } else {
+ acpi_remove_gpe_handler(NULL, ec->gpe,
+ &acpi_ec_gpe_handler);
+ return -ENODEV;
+ }
}
- ec->handlers_installed = 1;
+ set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
return 0;
}
@@ -887,7 +910,6 @@ static int acpi_ec_start(struct acpi_device *device)
/* EC is fully operational, allow queries */
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
- ec_schedule_ec_poll(ec);
return ret;
}
@@ -906,7 +928,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
int __init acpi_boot_ec_enable(void)
{
- if (!boot_ec || boot_ec->handlers_installed)
+ if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags))
return 0;
if (!ec_install_handlers(boot_ec)) {
first_ec = boot_ec;
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index 8892b9824fa..74da6fa52ef 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -43,7 +43,6 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
#include <acpi/actables.h>
#include <acpi/acdispat.h>
@@ -91,13 +90,12 @@ acpi_ex_add_table(u32 table_index,
/* Init the table handle */
- obj_desc->reference.opcode = AML_LOAD_OP;
+ obj_desc->reference.class = ACPI_REFCLASS_TABLE;
*ddb_handle = obj_desc;
/* Install the new table into the local data structures */
- obj_desc->reference.object = ACPI_CAST_PTR(void,
- (unsigned long)table_index);
+ obj_desc->reference.value = table_index;
/* Add the table to the namespace */
@@ -280,6 +278,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state)
{
union acpi_operand_object *ddb_handle;
+ struct acpi_table_header *table;
struct acpi_table_desc table_desc;
u32 table_index;
acpi_status status;
@@ -294,9 +293,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_REGION:
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
- obj_desc,
- acpi_ut_get_object_type_name(obj_desc)));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Load table from Region %p\n", obj_desc));
/* Region must be system_memory (from ACPI spec) */
@@ -316,61 +314,112 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
}
/*
- * We will simply map the memory region for the table. However, the
- * memory region is technically not guaranteed to remain stable and
- * we may eventually have to copy the table to a local buffer.
+ * Map the table header and get the actual table length. The region
+ * length is not guaranteed to be the same as the table length.
+ */
+ table = acpi_os_map_memory(obj_desc->region.address,
+ sizeof(struct acpi_table_header));
+ if (!table) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ length = table->length;
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+
+ /* Must have at least an ACPI table header */
+
+ if (length < sizeof(struct acpi_table_header)) {
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+ }
+
+ /*
+ * The memory region is not guaranteed to remain stable and we must
+ * copy the table to a local buffer. For example, the memory region
+ * is corrupted after suspend on some machines. Dynamically loaded
+ * tables are usually small, so this overhead is minimal.
*/
+
+ /* Allocate a buffer for the table */
+
+ table_desc.pointer = ACPI_ALLOCATE(length);
+ if (!table_desc.pointer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Map the entire table and copy it */
+
+ table = acpi_os_map_memory(obj_desc->region.address, length);
+ if (!table) {
+ ACPI_FREE(table_desc.pointer);
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ ACPI_MEMCPY(table_desc.pointer, table, length);
+ acpi_os_unmap_memory(table, length);
+
table_desc.address = obj_desc->region.address;
- table_desc.length = obj_desc->region.length;
- table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
break;
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Load from Buffer or Field %p %s\n", obj_desc,
- acpi_ut_get_object_type_name(obj_desc)));
-
- length = obj_desc->buffer.length;
+ "Load table from Buffer or Field %p\n",
+ obj_desc));
/* Must have at least an ACPI table header */
- if (length < sizeof(struct acpi_table_header)) {
+ if (obj_desc->buffer.length < sizeof(struct acpi_table_header)) {
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
}
- /* Validate checksum here. It won't get validated in tb_add_table */
+ /* Get the actual table length from the table header */
- status =
- acpi_tb_verify_checksum(ACPI_CAST_PTR
- (struct acpi_table_header,
- obj_desc->buffer.pointer), length);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ table =
+ ACPI_CAST_PTR(struct acpi_table_header,
+ obj_desc->buffer.pointer);
+ length = table->length;
+
+ /* Table cannot extend beyond the buffer */
+
+ if (length > obj_desc->buffer.length) {
+ return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
+ }
+ if (length < sizeof(struct acpi_table_header)) {
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
}
/*
- * We need to copy the buffer since the original buffer could be
- * changed or deleted in the future
+ * Copy the table from the buffer because the buffer could be modified
+ * or even deleted in the future
*/
table_desc.pointer = ACPI_ALLOCATE(length);
if (!table_desc.pointer) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer,
- length);
- table_desc.length = length;
- table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
+ ACPI_MEMCPY(table_desc.pointer, table, length);
+ table_desc.address = ACPI_TO_INTEGER(table_desc.pointer);
break;
default:
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- /*
- * Install the new table into the local data structures
- */
+ /* Validate table checksum (will not get validated in tb_add_table) */
+
+ status = acpi_tb_verify_checksum(table_desc.pointer, length);
+ if (ACPI_FAILURE(status)) {
+ ACPI_FREE(table_desc.pointer);
+ return_ACPI_STATUS(status);
+ }
+
+ /* Complete the table descriptor */
+
+ table_desc.length = length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
+
+ /* Install the new table into the local data structures */
+
status = acpi_tb_add_table(&table_desc, &table_index);
if (ACPI_FAILURE(status)) {
goto cleanup;
@@ -379,7 +428,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/*
* Add the table to the namespace.
*
- * Note: We load the table objects relative to the root of the namespace.
+ * Note: Load the table objects relative to the root of the namespace.
* This appears to go against the ACPI specification, but we do it for
* compatibility with other ACPI implementations.
*/
@@ -415,7 +464,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
cleanup:
if (ACPI_FAILURE(status)) {
- /* Delete allocated buffer or mapping */
+ /* Delete allocated table buffer */
acpi_tb_delete_table(&table_desc);
}
@@ -455,9 +504,9 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get the table index from the ddb_handle (acpi_size for 64-bit case) */
+ /* Get the table index from the ddb_handle */
- table_index = (u32) (acpi_size) table_desc->reference.object;
+ table_index = table_desc->reference.value;
/* Invoke table handler if present */
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index 261d97516d9..1d1f35adddd 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -57,7 +57,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
*
* FUNCTION: acpi_ex_convert_to_integer
*
- * PARAMETERS: obj_desc - Object to be converted. Must be an
+ * PARAMETERS: obj_desc - Object to be converted. Must be an
* Integer, Buffer, or String
* result_desc - Where the new Integer object is returned
* Flags - Used for string conversion
@@ -103,7 +103,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
}
/*
- * Convert the buffer/string to an integer. Note that both buffers and
+ * Convert the buffer/string to an integer. Note that both buffers and
* strings are treated as raw data - we don't convert ascii to hex for
* strings.
*
@@ -120,7 +120,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
/*
* Convert string to an integer - for most cases, the string must be
- * hexadecimal as per the ACPI specification. The only exception (as
+ * hexadecimal as per the ACPI specification. The only exception (as
* of ACPI 3.0) is that the to_integer() operator allows both decimal
* and hexadecimal strings (hex prefixed with "0x").
*/
@@ -159,6 +159,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
break;
default:
+
/* No other types can get here */
break;
}
@@ -185,7 +186,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
*
* FUNCTION: acpi_ex_convert_to_buffer
*
- * PARAMETERS: obj_desc - Object to be converted. Must be an
+ * PARAMETERS: obj_desc - Object to be converted. Must be an
* Integer, Buffer, or String
* result_desc - Where the new buffer object is returned
*
@@ -365,7 +366,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
}
/*
- * Since leading zeros are supressed, we must check for the case where
+ * Since leading zeros are suppressed, we must check for the case where
* the integer equals 0
*
* Finally, null terminate the string and return the length
@@ -383,7 +384,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
*
* FUNCTION: acpi_ex_convert_to_string
*
- * PARAMETERS: obj_desc - Object to be converted. Must be an
+ * PARAMETERS: obj_desc - Object to be converted. Must be an
* Integer, Buffer, or String
* result_desc - Where the string object is returned
* Type - String flags (base and conversion type)
@@ -472,7 +473,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
base = 10;
/*
- * Calculate the final string length. Individual string values
+ * Calculate the final string length. Individual string values
* are variable length (include separator for each)
*/
for (i = 0; i < obj_desc->buffer.length; i++) {
@@ -511,9 +512,14 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
/*
* Create a new string object and string buffer
* (-1 because of extra separator included in string_length from above)
+ * Allow creation of zero-length strings from zero-length buffers.
*/
+ if (string_length) {
+ string_length--;
+ }
+
return_desc = acpi_ut_create_string_object((acpi_size)
- (string_length - 1));
+ string_length);
if (!return_desc) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -536,7 +542,9 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
* Null terminate the string
* (overwrites final comma/space from above)
*/
- new_buf--;
+ if (obj_desc->buffer.length) {
+ new_buf--;
+ }
*new_buf = 0;
break;
@@ -617,7 +625,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
case ACPI_TYPE_LOCAL_BANK_FIELD:
case ACPI_TYPE_LOCAL_INDEX_FIELD:
/*
- * These types require an Integer operand. We can convert
+ * These types require an Integer operand. We can convert
* a Buffer or a String to an Integer if necessary.
*/
status =
@@ -627,7 +635,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
case ACPI_TYPE_STRING:
/*
- * The operand must be a String. We can convert an
+ * The operand must be a String. We can convert an
* Integer or Buffer if necessary
*/
status =
@@ -637,7 +645,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
case ACPI_TYPE_BUFFER:
/*
- * The operand must be a Buffer. We can convert an
+ * The operand must be a Buffer. We can convert an
* Integer or String if necessary
*/
status =
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 2be2e2bf95b..d087a7d28aa 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -45,7 +45,6 @@
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exdump")
@@ -214,10 +213,11 @@ static struct acpi_exdump_info acpi_ex_dump_index_field[5] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(index_field.data_obj), "Data Object"}
};
-static struct acpi_exdump_info acpi_ex_dump_reference[7] = {
+static struct acpi_exdump_info acpi_ex_dump_reference[8] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_reference), NULL},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.class), "Class"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.target_type), "Target Type"},
- {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(reference.offset), "Offset"},
+ {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(reference.value), "Value"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.object), "Object Desc"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.node), "Node"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.where), "Where"},
@@ -413,10 +413,10 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
case ACPI_EXD_REFERENCE:
- acpi_ex_out_string("Opcode",
- (acpi_ps_get_opcode_info
- (obj_desc->reference.opcode))->
- name);
+ acpi_ex_out_string("Class Name",
+ (char *)
+ acpi_ut_get_reference_name
+ (obj_desc));
acpi_ex_dump_reference_obj(obj_desc);
break;
@@ -494,40 +494,41 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE:
- switch (obj_desc->reference.opcode) {
- case AML_DEBUG_OP:
+ acpi_os_printf("Reference: [%s] ",
+ acpi_ut_get_reference_name(obj_desc));
+
+ switch (obj_desc->reference.class) {
+ case ACPI_REFCLASS_DEBUG:
- acpi_os_printf("Reference: Debug\n");
+ acpi_os_printf("\n");
break;
- case AML_INDEX_OP:
+ case ACPI_REFCLASS_INDEX:
- acpi_os_printf("Reference: Index %p\n",
- obj_desc->reference.object);
+ acpi_os_printf("%p\n", obj_desc->reference.object);
break;
- case AML_LOAD_OP:
+ case ACPI_REFCLASS_TABLE:
- acpi_os_printf("Reference: [DdbHandle] TableIndex %p\n",
- obj_desc->reference.object);
+ acpi_os_printf("Table Index %X\n",
+ obj_desc->reference.value);
break;
- case AML_REF_OF_OP:
+ case ACPI_REFCLASS_REFOF:
- acpi_os_printf("Reference: (RefOf) %p [%s]\n",
- obj_desc->reference.object,
+ acpi_os_printf("%p [%s]\n", obj_desc->reference.object,
acpi_ut_get_type_name(((union
acpi_operand_object
- *)obj_desc->
+ *)
+ obj_desc->
reference.
object)->common.
type));
break;
- case AML_ARG_OP:
+ case ACPI_REFCLASS_ARG:
- acpi_os_printf("Reference: Arg%d",
- obj_desc->reference.offset);
+ acpi_os_printf("%X", obj_desc->reference.value);
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
@@ -542,10 +543,9 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
acpi_os_printf("\n");
break;
- case AML_LOCAL_OP:
+ case ACPI_REFCLASS_LOCAL:
- acpi_os_printf("Reference: Local%d",
- obj_desc->reference.offset);
+ acpi_os_printf("%X", obj_desc->reference.value);
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
@@ -560,21 +560,16 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
acpi_os_printf("\n");
break;
- case AML_INT_NAMEPATH_OP:
+ case ACPI_REFCLASS_NAME:
- acpi_os_printf("Reference: Namepath %X [%4.4s]\n",
- obj_desc->reference.node->name.integer,
+ acpi_os_printf("- [%4.4s]\n",
obj_desc->reference.node->name.ascii);
break;
- default:
-
- /* Unknown opcode */
+ default: /* Unknown reference class */
- acpi_os_printf("Unknown Reference opcode=%X\n",
- obj_desc->reference.opcode);
+ acpi_os_printf("%2.2X\n", obj_desc->reference.class);
break;
-
}
break;
@@ -865,8 +860,8 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc)
ret_buf.length = ACPI_ALLOCATE_LOCAL_BUFFER;
- if (obj_desc->reference.opcode == AML_INT_NAMEPATH_OP) {
- acpi_os_printf(" Named Object %p ", obj_desc->reference.node);
+ if (obj_desc->reference.class == ACPI_REFCLASS_NAME) {
+ acpi_os_printf(" %p ", obj_desc->reference.node);
status =
acpi_ns_handle_to_pathname(obj_desc->reference.node,
@@ -882,14 +877,12 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc)
ACPI_DESC_TYPE_OPERAND) {
acpi_os_printf(" Target: %p",
obj_desc->reference.object);
- if (obj_desc->reference.opcode == AML_LOAD_OP) {
- /*
- * For DDBHandle reference,
- * obj_desc->Reference.Object is the table index
- */
- acpi_os_printf(" [DDBHandle]\n");
+ if (obj_desc->reference.class == ACPI_REFCLASS_TABLE) {
+ acpi_os_printf(" Table Index: %X\n",
+ obj_desc->reference.value);
} else {
- acpi_os_printf(" [%s]\n",
+ acpi_os_printf(" Target: %p [%s]\n",
+ obj_desc->reference.object,
acpi_ut_get_type_name(((union
acpi_operand_object
*)
@@ -988,9 +981,9 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc,
case ACPI_TYPE_LOCAL_REFERENCE:
- acpi_os_printf("[Object Reference] %s",
- (acpi_ps_get_opcode_info
- (obj_desc->reference.opcode))->name);
+ acpi_os_printf("[Object Reference] Type [%s] %2.2X",
+ acpi_ut_get_reference_name(obj_desc),
+ obj_desc->reference.class);
acpi_ex_dump_reference_obj(obj_desc);
break;
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index 731414a581a..efb19134005 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -86,10 +86,10 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
/*
* Must be a reference to a Local or Arg
*/
- switch (obj_desc->reference.opcode) {
- case AML_LOCAL_OP:
- case AML_ARG_OP:
- case AML_DEBUG_OP:
+ switch (obj_desc->reference.class) {
+ case ACPI_REFCLASS_LOCAL:
+ case ACPI_REFCLASS_ARG:
+ case ACPI_REFCLASS_DEBUG:
/* The referenced object is the pseudo-node for the local/arg */
@@ -98,8 +98,8 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
default:
- ACPI_ERROR((AE_INFO, "Unknown Reference opcode %X",
- obj_desc->reference.opcode));
+ ACPI_ERROR((AE_INFO, "Unknown Reference Class %2.2X",
+ obj_desc->reference.class));
return_ACPI_STATUS(AE_AML_INTERNAL);
}
break;
@@ -127,7 +127,7 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_NO_MEMORY);
}
- reference_obj->reference.opcode = AML_REF_OF_OP;
+ reference_obj->reference.class = ACPI_REFCLASS_REFOF;
reference_obj->reference.object = referenced_obj;
*return_desc = reference_obj;
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
index 7c3bea575e0..f622f9eac8a 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -825,16 +825,16 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
*
* Must resolve/dereference the local/arg reference first
*/
- switch (operand[0]->reference.opcode) {
- case AML_LOCAL_OP:
- case AML_ARG_OP:
+ switch (operand[0]->reference.class) {
+ case ACPI_REFCLASS_LOCAL:
+ case ACPI_REFCLASS_ARG:
/* Set Operand[0] to the value of the local/arg */
status =
acpi_ds_method_data_get_value
- (operand[0]->reference.opcode,
- operand[0]->reference.offset,
+ (operand[0]->reference.class,
+ operand[0]->reference.value,
walk_state, &temp_desc);
if (ACPI_FAILURE(status)) {
goto cleanup;
@@ -848,7 +848,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
operand[0] = temp_desc;
break;
- case AML_REF_OF_OP:
+ case ACPI_REFCLASS_REFOF:
/* Get the object to which the reference refers */
@@ -928,8 +928,8 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
* This must be a reference object produced by either the
* Index() or ref_of() operator
*/
- switch (operand[0]->reference.opcode) {
- case AML_INDEX_OP:
+ switch (operand[0]->reference.class) {
+ case ACPI_REFCLASS_INDEX:
/*
* The target type for the Index operator must be
@@ -965,7 +965,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
return_desc->integer.value =
temp_desc->buffer.
pointer[operand[0]->reference.
- offset];
+ value];
break;
case ACPI_TYPE_PACKAGE:
@@ -985,7 +985,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
default:
ACPI_ERROR((AE_INFO,
- "Unknown Index TargetType %X in obj %p",
+ "Unknown Index TargetType %X in reference object %p",
operand[0]->reference.
target_type, operand[0]));
status = AE_AML_OPERAND_TYPE;
@@ -993,7 +993,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
}
break;
- case AML_REF_OF_OP:
+ case ACPI_REFCLASS_REFOF:
return_desc = operand[0]->reference.object;
@@ -1013,9 +1013,9 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
default:
ACPI_ERROR((AE_INFO,
- "Unknown opcode in reference(%p) - %X",
+ "Unknown class in reference(%p) - %2.2X",
operand[0],
- operand[0]->reference.opcode));
+ operand[0]->reference.class));
status = AE_TYPE;
goto cleanup;
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index 8e8bbb6cceb..368def5dffc 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -391,8 +391,8 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
/* Initialize the Index reference object */
index = operand[1]->integer.value;
- return_desc->reference.offset = (u32) index;
- return_desc->reference.opcode = AML_INDEX_OP;
+ return_desc->reference.value = (u32) index;
+ return_desc->reference.class = ACPI_REFCLASS_INDEX;
/*
* At this point, the Source operand is a String, Buffer, or Package.
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 5596f42c967..423ad3635f3 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -46,8 +46,6 @@
#include <acpi/acdispat.h>
#include <acpi/acinterp.h>
#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exresnte")
@@ -238,10 +236,10 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
case ACPI_TYPE_LOCAL_REFERENCE:
- switch (source_desc->reference.opcode) {
- case AML_LOAD_OP: /* This is a ddb_handle */
- case AML_REF_OF_OP:
- case AML_INDEX_OP:
+ switch (source_desc->reference.class) {
+ case ACPI_REFCLASS_TABLE: /* This is a ddb_handle */
+ case ACPI_REFCLASS_REFOF:
+ case ACPI_REFCLASS_INDEX:
/* Return an additional reference to the object */
@@ -253,10 +251,8 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
/* No named references are allowed here */
ACPI_ERROR((AE_INFO,
- "Unsupported Reference opcode %X (%s)",
- source_desc->reference.opcode,
- acpi_ps_get_opcode_name(source_desc->
- reference.opcode)));
+ "Unsupported Reference type %X",
+ source_desc->reference.class));
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index b35f7c817ac..89571b92a52 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -47,7 +47,6 @@
#include <acpi/acdispat.h>
#include <acpi/acinterp.h>
#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exresolv")
@@ -141,7 +140,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
acpi_status status = AE_OK;
union acpi_operand_object *stack_desc;
union acpi_operand_object *obj_desc = NULL;
- u16 opcode;
+ u8 ref_type;
ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
@@ -152,19 +151,19 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
switch (ACPI_GET_OBJECT_TYPE(stack_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE:
- opcode = stack_desc->reference.opcode;
+ ref_type = stack_desc->reference.class;
- switch (opcode) {
- case AML_LOCAL_OP:
- case AML_ARG_OP:
+ switch (ref_type) {
+ case ACPI_REFCLASS_LOCAL:
+ case ACPI_REFCLASS_ARG:
/*
* Get the local from the method's state info
* Note: this increments the local's object reference count
*/
- status = acpi_ds_method_data_get_value(opcode,
+ status = acpi_ds_method_data_get_value(ref_type,
stack_desc->
- reference.offset,
+ reference.value,
walk_state,
&obj_desc);
if (ACPI_FAILURE(status)) {
@@ -173,7 +172,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"[Arg/Local %X] ValueObj is %p\n",
- stack_desc->reference.offset,
+ stack_desc->reference.value,
obj_desc));
/*
@@ -184,7 +183,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
*stack_ptr = obj_desc;
break;
- case AML_INDEX_OP:
+ case ACPI_REFCLASS_INDEX:
switch (stack_desc->reference.target_type) {
case ACPI_TYPE_BUFFER_FIELD:
@@ -239,15 +238,15 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
}
break;
- case AML_REF_OF_OP:
- case AML_DEBUG_OP:
- case AML_LOAD_OP:
+ case ACPI_REFCLASS_REFOF:
+ case ACPI_REFCLASS_DEBUG:
+ case ACPI_REFCLASS_TABLE:
/* Just leave the object as-is, do not dereference */
break;
- case AML_INT_NAMEPATH_OP: /* Reference to a named object */
+ case ACPI_REFCLASS_NAME: /* Reference to a named object */
/* Dereference the name */
@@ -273,8 +272,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
default:
ACPI_ERROR((AE_INFO,
- "Unknown Reference opcode %X (%s) in %p",
- opcode, acpi_ps_get_opcode_name(opcode),
+ "Unknown Reference type %X in %p", ref_type,
stack_desc));
status = AE_AML_INTERNAL;
break;
@@ -388,13 +386,13 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
* traversing the list of possibly many nested references.
*/
while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
- switch (obj_desc->reference.opcode) {
- case AML_REF_OF_OP:
- case AML_INT_NAMEPATH_OP:
+ switch (obj_desc->reference.class) {
+ case ACPI_REFCLASS_REFOF:
+ case ACPI_REFCLASS_NAME:
/* Dereference the reference pointer */
- if (obj_desc->reference.opcode == AML_REF_OF_OP) {
+ if (obj_desc->reference.class == ACPI_REFCLASS_REFOF) {
node = obj_desc->reference.object;
} else { /* AML_INT_NAMEPATH_OP */
@@ -429,7 +427,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
}
break;
- case AML_INDEX_OP:
+ case ACPI_REFCLASS_INDEX:
/* Get the type of this reference (index into another object) */
@@ -455,22 +453,22 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
}
break;
- case AML_LOAD_OP:
+ case ACPI_REFCLASS_TABLE:
type = ACPI_TYPE_DDB_HANDLE;
goto exit;
- case AML_LOCAL_OP:
- case AML_ARG_OP:
+ case ACPI_REFCLASS_LOCAL:
+ case ACPI_REFCLASS_ARG:
if (return_desc) {
status =
acpi_ds_method_data_get_value(obj_desc->
reference.
- opcode,
+ class,
obj_desc->
reference.
- offset,
+ value,
walk_state,
&obj_desc);
if (ACPI_FAILURE(status)) {
@@ -481,10 +479,10 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
status =
acpi_ds_method_data_get_node(obj_desc->
reference.
- opcode,
+ class,
obj_desc->
reference.
- offset,
+ value,
walk_state,
&node);
if (ACPI_FAILURE(status)) {
@@ -499,7 +497,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
}
break;
- case AML_DEBUG_OP:
+ case ACPI_REFCLASS_DEBUG:
/* The Debug Object is of type "DebugObject" */
@@ -509,8 +507,8 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
default:
ACPI_ERROR((AE_INFO,
- "Unknown Reference subtype %X",
- obj_desc->reference.opcode));
+ "Unknown Reference Class %2.2X",
+ obj_desc->reference.class));
return_ACPI_STATUS(AE_AML_INTERNAL);
}
}
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index 54085f16ec2..0bb82593da7 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -225,41 +225,36 @@ acpi_ex_resolve_operands(u16 opcode,
if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) {
- /* Decode the Reference */
+ /* Validate the Reference */
- op_info = acpi_ps_get_opcode_info(opcode);
- if (op_info->class == AML_CLASS_UNKNOWN) {
- return_ACPI_STATUS(AE_AML_BAD_OPCODE);
- }
+ switch (obj_desc->reference.class) {
+ case ACPI_REFCLASS_DEBUG:
- switch (obj_desc->reference.opcode) {
- case AML_DEBUG_OP:
target_op = AML_DEBUG_OP;
/*lint -fallthrough */
- case AML_INDEX_OP:
- case AML_REF_OF_OP:
- case AML_ARG_OP:
- case AML_LOCAL_OP:
- case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
- case AML_INT_NAMEPATH_OP: /* Reference to a named object */
-
- ACPI_DEBUG_ONLY_MEMBERS(ACPI_DEBUG_PRINT
- ((ACPI_DB_EXEC,
- "Operand is a Reference, RefOpcode [%s]\n",
- (acpi_ps_get_opcode_info
- (obj_desc->
- reference.
- opcode))->
- name)));
+ case ACPI_REFCLASS_ARG:
+ case ACPI_REFCLASS_LOCAL:
+ case ACPI_REFCLASS_INDEX:
+ case ACPI_REFCLASS_REFOF:
+ case ACPI_REFCLASS_TABLE: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
+ case ACPI_REFCLASS_NAME: /* Reference to a named object */
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Operand is a Reference, Class [%s] %2.2X\n",
+ acpi_ut_get_reference_name
+ (obj_desc),
+ obj_desc->reference.
+ class));
break;
default:
+
ACPI_ERROR((AE_INFO,
- "Operand is a Reference, Unknown Reference Opcode: %X",
- obj_desc->reference.
- opcode));
+ "Unknown Reference Class %2.2X in %p",
+ obj_desc->reference.class,
+ obj_desc));
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
@@ -270,8 +265,7 @@ acpi_ex_resolve_operands(u16 opcode,
/* Invalid descriptor */
- ACPI_ERROR((AE_INFO,
- "Invalid descriptor %p [%s]",
+ ACPI_ERROR((AE_INFO, "Invalid descriptor %p [%s]",
obj_desc,
acpi_ut_get_descriptor_name(obj_desc)));
@@ -343,7 +337,7 @@ acpi_ex_resolve_operands(u16 opcode,
if ((opcode == AML_STORE_OP) &&
(ACPI_GET_OBJECT_TYPE(*stack_ptr) ==
ACPI_TYPE_LOCAL_REFERENCE)
- && ((*stack_ptr)->reference.opcode == AML_INDEX_OP)) {
+ && ((*stack_ptr)->reference.class == ACPI_REFCLASS_INDEX)) {
goto next_operand;
}
break;
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index 38b55e35249..3318df4cbd9 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -47,7 +47,6 @@
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exstore")
@@ -179,22 +178,26 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
case ACPI_TYPE_LOCAL_REFERENCE:
- if (source_desc->reference.opcode == AML_INDEX_OP) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
- "[%s, 0x%X]\n",
- acpi_ps_get_opcode_name
- (source_desc->reference.opcode),
- source_desc->reference.offset));
- } else {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]",
- acpi_ps_get_opcode_name
- (source_desc->reference.opcode)));
- }
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s] ",
+ acpi_ut_get_reference_name(source_desc)));
+
+ /* Decode the reference */
+
+ switch (source_desc->reference.class) {
+ case ACPI_REFCLASS_INDEX:
+
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "0x%X\n",
+ source_desc->reference.value));
+ break;
+
+ case ACPI_REFCLASS_TABLE:
- if (source_desc->reference.opcode == AML_LOAD_OP) { /* Load and load_table */
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
- " Table OwnerId %p\n",
- source_desc->reference.object));
+ "Table Index 0x%X\n",
+ source_desc->reference.value));
+ break;
+
+ default:
break;
}
@@ -347,15 +350,15 @@ acpi_ex_store(union acpi_operand_object *source_desc,
}
/*
- * Examine the Reference opcode. These cases are handled:
+ * Examine the Reference class. These cases are handled:
*
* 1) Store to Name (Change the object associated with a name)
* 2) Store to an indexed area of a Buffer or Package
* 3) Store to a Method Local or Arg
* 4) Store to the debug object
*/
- switch (ref_desc->reference.opcode) {
- case AML_REF_OF_OP:
+ switch (ref_desc->reference.class) {
+ case ACPI_REFCLASS_REFOF:
/* Storing an object into a Name "container" */
@@ -365,7 +368,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
ACPI_IMPLICIT_CONVERSION);
break;
- case AML_INDEX_OP:
+ case ACPI_REFCLASS_INDEX:
/* Storing to an Index (pointer into a packager or buffer) */
@@ -374,18 +377,18 @@ acpi_ex_store(union acpi_operand_object *source_desc,
walk_state);
break;
- case AML_LOCAL_OP:
- case AML_ARG_OP:
+ case ACPI_REFCLASS_LOCAL:
+ case ACPI_REFCLASS_ARG:
/* Store to a method local/arg */
status =
- acpi_ds_store_object_to_local(ref_desc->reference.opcode,
- ref_desc->reference.offset,
+ acpi_ds_store_object_to_local(ref_desc->reference.class,
+ ref_desc->reference.value,
source_desc, walk_state);
break;
- case AML_DEBUG_OP:
+ case ACPI_REFCLASS_DEBUG:
/*
* Storing to the Debug object causes the value stored to be
@@ -401,9 +404,9 @@ acpi_ex_store(union acpi_operand_object *source_desc,
default:
- ACPI_ERROR((AE_INFO, "Unknown Reference opcode %X",
- ref_desc->reference.opcode));
- ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_ERROR);
+ ACPI_ERROR((AE_INFO, "Unknown Reference Class %2.2X",
+ ref_desc->reference.class));
+ ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_INFO);
status = AE_AML_INTERNAL;
break;
@@ -458,7 +461,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
if (ACPI_GET_OBJECT_TYPE(source_desc) ==
ACPI_TYPE_LOCAL_REFERENCE
- && source_desc->reference.opcode == AML_LOAD_OP) {
+ && source_desc->reference.class == ACPI_REFCLASS_TABLE) {
/* This is a DDBHandle, just add a reference to it */
@@ -553,7 +556,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
/* Store the source value into the target buffer byte */
- obj_desc->buffer.pointer[index_desc->reference.offset] = value;
+ obj_desc->buffer.pointer[index_desc->reference.value] = value;
break;
default:
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index a6d2168b81f..eef61a00803 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -121,7 +121,8 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
(ACPI_GET_OBJECT_TYPE(source_desc) != ACPI_TYPE_STRING) &&
!((ACPI_GET_OBJECT_TYPE(source_desc) ==
ACPI_TYPE_LOCAL_REFERENCE)
- && (source_desc->reference.opcode == AML_LOAD_OP))) {
+ && (source_desc->reference.class ==
+ ACPI_REFCLASS_TABLE))) {
/* Conversion successful but still not a valid type */
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 2655bc1b4ee..60d54d1f6b1 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -265,7 +265,7 @@ static int acpi_fan_add(struct acpi_device *device)
dev_info(&device->dev, "registered as cooling_device%d\n", cdev->id);
- acpi_driver_data(device) = cdev;
+ device->driver_data = cdev;
result = sysfs_create_link(&device->dev.kobj,
&cdev->device.kobj,
"thermal_cooling");
@@ -327,8 +327,8 @@ static int acpi_fan_resume(struct acpi_device *device)
result = acpi_bus_get_power(device->handle, &power_state);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error reading fan power state\n"));
+ printk(KERN_ERR PREFIX
+ "Error reading fan power state\n");
return result;
}
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index dba3cfbe8cb..25dccdf179b 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -78,19 +78,17 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
return_ACPI_STATUS(status);
}
- /* Set the vector */
+ /*
+ * According to the ACPI specification 2.0c and later, the 64-bit
+ * waking vector should be cleared and the 32-bit waking vector should
+ * be used, unless we want the wake-up code to be called by the BIOS in
+ * 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;
- if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
- /*
- * ACPI 1.0 FACS or short table or optional X_ field is zero
- */
- facs->firmware_waking_vector = (u32) physical_address;
- } else {
- /*
- * ACPI 2.0 FACS with valid X_ field
- */
- facs->xfirmware_waking_vector = physical_address;
- }
+ facs->firmware_waking_vector = (u32)physical_address;
return_ACPI_STATUS(AE_OK);
}
@@ -134,20 +132,7 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
}
/* Get the vector */
-
- if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
- /*
- * ACPI 1.0 FACS or short table or optional X_ field is zero
- */
- *physical_address =
- (acpi_physical_address) facs->firmware_waking_vector;
- } else {
- /*
- * ACPI 2.0 FACS with valid X_ field
- */
- *physical_address =
- (acpi_physical_address) facs->xfirmware_waking_vector;
- }
+ *physical_address = (acpi_physical_address)facs->firmware_waking_vector;
return_ACPI_STATUS(AE_OK);
}
@@ -627,6 +612,13 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
}
/* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
+ /*
+ * Some BIOSes assume that WAK_STS will be cleared on resume and use
+ * it to determine whether the system is rebooting or resuming. Clear
+ * it for compatibility.
+ */
+ acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
+
acpi_gbl_system_awake_and_running = TRUE;
/* Enable power button */
diff --git a/drivers/acpi/namespace/Makefile b/drivers/acpi/namespace/Makefile
index 3f63d364069..371a2daf837 100644
--- a/drivers/acpi/namespace/Makefile
+++ b/drivers/acpi/namespace/Makefile
@@ -5,7 +5,7 @@
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
+ nsparse.o nspredef.o
obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index 0ab22004728..cc0ae39440e 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -43,7 +43,6 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsdump")
@@ -334,9 +333,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
case ACPI_TYPE_LOCAL_REFERENCE:
acpi_os_printf("[%s]\n",
- acpi_ps_get_opcode_name(obj_desc->
- reference.
- opcode));
+ acpi_ut_get_reference_name(obj_desc));
break;
case ACPI_TYPE_BUFFER_FIELD:
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index d369164e00b..4cdf03ac2b4 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -78,6 +78,7 @@ ACPI_MODULE_NAME("nseval")
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
{
acpi_status status;
+ struct acpi_namespace_node *node;
ACPI_FUNCTION_TRACE(ns_evaluate);
@@ -117,6 +118,8 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
info->resolved_node,
acpi_ns_get_attached_object(info->resolved_node)));
+ node = info->resolved_node;
+
/*
* Two major cases here:
*
@@ -148,21 +151,22 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
info->param_count++;
}
- /* Error if too few arguments were passed in */
+ /*
+ * 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_ERROR((AE_INFO,
+ 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));
- return_ACPI_STATUS(AE_MISSING_ARGUMENTS);
- }
-
- /* Just a warning if too many arguments */
-
- else if (info->param_count >
+ } else if (info->param_count >
info->obj_desc->method.param_count) {
ACPI_WARNING((AE_INFO,
"Excess arguments - "
@@ -195,7 +199,28 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
} else {
/*
* 2) Object is not a method, return its current value
+ *
+ * Disallow certain object types. For these, "evaluation" is undefined.
*/
+ switch (info->resolved_node->type) {
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_EVENT:
+ case ACPI_TYPE_MUTEX:
+ case ACPI_TYPE_REGION:
+ case ACPI_TYPE_THERMAL:
+ case ACPI_TYPE_LOCAL_SCOPE:
+
+ ACPI_ERROR((AE_INFO,
+ "[%4.4s] Evaluation of object type [%s] is not supported",
+ info->resolved_node->name.ascii,
+ acpi_ut_get_type_name(info->resolved_node->
+ type)));
+
+ return_ACPI_STATUS(AE_TYPE);
+
+ default:
+ break;
+ }
/*
* Objects require additional resolution steps (e.g., the Node may be
@@ -239,9 +264,35 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
}
}
- /*
- * Check if there is a return value that must be dealt with
- */
+ /* 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 if there is a return value that must be dealt with */
+
if (status == AE_CTRL_RETURN_VALUE) {
/* If caller does not want the return value, delete it */
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index bd577387800..42a39a7c96e 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -115,7 +115,6 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node,
return (AE_OK);
}
-#ifdef ACPI_DEBUG_OUTPUT
/*******************************************************************************
*
* FUNCTION: acpi_ns_get_external_pathname
@@ -142,7 +141,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
size = acpi_ns_get_pathname_length(node);
if (!size) {
- return (NULL);
+ return_PTR(NULL);
}
/* Allocate a buffer to be returned to caller */
@@ -157,12 +156,12 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
status = acpi_ns_build_external_path(node, size, name_buffer);
if (ACPI_FAILURE(status)) {
- return (NULL);
+ ACPI_FREE(name_buffer);
+ return_PTR(NULL);
}
return_PTR(name_buffer);
}
-#endif
/*******************************************************************************
*
diff --git a/drivers/acpi/namespace/nspredef.c b/drivers/acpi/namespace/nspredef.c
new file mode 100644
index 00000000000..0f17cf0898c
--- /dev/null
+++ b/drivers/acpi/namespace/nspredef.c
@@ -0,0 +1,900 @@
+/******************************************************************************
+ *
+ * Module Name: nspredef - Validation of 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.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acpredef.h>
+
+#define _COMPONENT ACPI_NAMESPACE
+ACPI_MODULE_NAME("nspredef")
+
+/*******************************************************************************
+ *
+ * This module validates predefined ACPI objects that appear in the namespace,
+ * at the time they are evaluated (via acpi_evaluate_object). The purpose of this
+ * validation is to detect problems with BIOS-exposed predefined ACPI objects
+ * before the results are returned to the ACPI-related drivers.
+ *
+ * There are several areas that are validated:
+ *
+ * 1) The number of input arguments as defined by the method/object in the
+ * ASL is validated against the ACPI specification.
+ * 2) The type of the return object (if any) is validated against the ACPI
+ * specification.
+ * 3) For returned package objects, the count of package elements is
+ * validated, as well as the type of each package element. Nested
+ * packages are supported.
+ *
+ * For any problems found, a warning message is issued.
+ *
+ ******************************************************************************/
+/* Local prototypes */
+static acpi_status
+acpi_ns_check_package(char *pathname,
+ union acpi_operand_object *return_object,
+ const union acpi_predefined_info *predefined);
+
+static acpi_status
+acpi_ns_check_package_elements(char *pathname,
+ union acpi_operand_object **elements,
+ u8 type1, u32 count1, u8 type2, u32 count2);
+
+static acpi_status
+acpi_ns_check_object_type(char *pathname,
+ union acpi_operand_object *return_object,
+ u32 expected_btypes, u32 package_index);
+
+static acpi_status
+acpi_ns_check_reference(char *pathname,
+ union acpi_operand_object *return_object);
+
+/*
+ * 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
+ */
+static const char *acpi_rtype_names[] = {
+ "/Integer",
+ "/String",
+ "/Buffer",
+ "/Package",
+ "/Reference",
+};
+
+#define ACPI_NOT_PACKAGE ACPI_UINT32_MAX
+
+/*******************************************************************************
+ *
+ * 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: Status
+ *
+ * DESCRIPTION: Check an ACPI name for a match in the predefined name list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
+ union acpi_operand_object *return_object)
+{
+ acpi_status status = AE_OK;
+ const union acpi_predefined_info *predefined;
+ char *pathname;
+
+ /* 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 */
+
+ pathname = acpi_ns_get_external_pathname(node);
+ if (!pathname) {
+ pathname = ACPI_CAST_PTR(char, predefined->info.name);
+ }
+
+ /*
+ * Check that the parameter count for this method is in accordance
+ * with the ACPI specification.
+ */
+ acpi_ns_check_parameter_count(pathname, node, predefined);
+
+ /*
+ * If there is no return value, check if we require a return value for
+ * this predefined name. Either one return value is expected, or none,
+ * for both methods and other objects.
+ *
+ * Exit now if there is no return object. Warning if one was expected.
+ */
+ if (!return_object) {
+ if ((predefined->info.expected_btypes) &&
+ (!(predefined->info.expected_btypes & ACPI_RTYPE_NONE))) {
+ ACPI_ERROR((AE_INFO,
+ "%s: Missing expected return value",
+ pathname));
+
+ status = AE_AML_NO_RETURN_VALUE;
+ }
+ goto exit;
+ }
+
+ /*
+ * 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
+ * always return a value
+ */
+ if (!predefined->info.expected_btypes) {
+ goto exit;
+ }
+
+ /*
+ * 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,
+ predefined->info.expected_btypes,
+ ACPI_NOT_PACKAGE);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ /* For returned Package objects, check the type of all sub-objects */
+
+ if (ACPI_GET_OBJECT_TYPE(return_object) == ACPI_TYPE_PACKAGE) {
+ status =
+ acpi_ns_check_package(pathname, return_object, predefined);
+ }
+
+ exit:
+ if (pathname) {
+ ACPI_FREE(pathname);
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_parameter_count
+ *
+ * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * Node - Namespace node for the method/object
+ * Predefined - Pointer to entry in predefined name table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Check that the declared (in ASL/AML) parameter count for a
+ * predefined name is what is expected (i.e., what is defined in
+ * the ACPI specification for this predefined name.)
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_check_parameter_count(char *pathname,
+ struct acpi_namespace_node *node,
+ 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.
+ */
+ 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) */
+
+ required_params_current = predefined->info.param_count & 0x0F;
+ required_params_old = predefined->info.param_count >> 4;
+
+ if ((param_count != required_params_current) &&
+ (param_count != required_params_old)) {
+ ACPI_WARNING((AE_INFO,
+ "%s: Parameter count mismatch - ASL declared %d, expected %d",
+ pathname, param_count, required_params_current));
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_for_predefined_name
+ *
+ * PARAMETERS: Node - Namespace node for the method/object
+ *
+ * RETURN: Pointer to entry in predefined table. NULL indicates not found.
+ *
+ * DESCRIPTION: Check an object name against the predefined object list.
+ *
+ ******************************************************************************/
+
+const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
+ acpi_namespace_node
+ *node)
+{
+ const union acpi_predefined_info *this_name;
+
+ /* Quick check for a predefined name, first character must be underscore */
+
+ if (node->name.ascii[0] != '_') {
+ return (NULL);
+ }
+
+ /* Search info table for a predefined method/object name */
+
+ this_name = predefined_names;
+ while (this_name->info.name[0]) {
+ if (ACPI_COMPARE_NAME(node->name.ascii, this_name->info.name)) {
+
+ /* Return pointer to this table entry */
+
+ return (this_name);
+ }
+
+ /*
+ * Skip next entry in the table if this name returns a Package
+ * (next entry contains the package info)
+ */
+ if (this_name->info.expected_btypes & ACPI_RTYPE_PACKAGE) {
+ this_name++;
+ }
+
+ this_name++;
+ }
+
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * 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
+ * Predefined - Pointer to entry in predefined name table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check a returned package object for the correct count and
+ * correct type of all sub-objects.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_check_package(char *pathname,
+ union acpi_operand_object *return_object,
+ const union acpi_predefined_info *predefined)
+{
+ const union acpi_predefined_info *package;
+ union acpi_operand_object *sub_package;
+ union acpi_operand_object **elements;
+ union acpi_operand_object **sub_elements;
+ acpi_status status;
+ u32 expected_count;
+ u32 count;
+ u32 i;
+ u32 j;
+
+ ACPI_FUNCTION_NAME(ns_check_package);
+
+ /* The package info for this name is in the next table entry */
+
+ package = predefined + 1;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
+ "%s Validating return Package of Type %X, Count %X\n",
+ pathname, package->ret_info.type,
+ return_object->package.count));
+
+ /* Extract package count and elements array */
+
+ elements = return_object->package.elements;
+ count = return_object->package.count;
+
+ /* The package must have at least one element, else invalid */
+
+ if (!count) {
+ ACPI_WARNING((AE_INFO,
+ "%s: Return Package has no elements (empty)",
+ pathname));
+
+ return (AE_AML_OPERAND_VALUE);
+ }
+
+ /*
+ * Decode the type of the expected package contents
+ *
+ * PTYPE1 packages contain no subpackages
+ * PTYPE2 packages contain sub-packages
+ */
+ switch (package->ret_info.type) {
+ case ACPI_PTYPE1_FIXED:
+
+ /*
+ * The package count is fixed and there are no sub-packages
+ *
+ * If package is too small, exit.
+ * If package is larger than expected, issue warning but continue
+ */
+ expected_count =
+ package->ret_info.count1 + package->ret_info.count2;
+ if (count < expected_count) {
+ goto package_too_small;
+ } else if (count > expected_count) {
+ ACPI_WARNING((AE_INFO,
+ "%s: Return Package is larger than needed - "
+ "found %u, expected %u", pathname, count,
+ expected_count));
+ }
+
+ /* Validate all elements of the returned package */
+
+ status = acpi_ns_check_package_elements(pathname, elements,
+ package->ret_info.
+ object_type1,
+ package->ret_info.
+ count1,
+ package->ret_info.
+ object_type2,
+ package->ret_info.
+ count2);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_PTYPE1_VAR:
+
+ /*
+ * The package count is variable, there are no sub-packages, and all
+ * elements must be of the same type
+ */
+ for (i = 0; i < count; i++) {
+ status = acpi_ns_check_object_type(pathname, *elements,
+ package->ret_info.
+ object_type1, i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ elements++;
+ }
+ break;
+
+ case ACPI_PTYPE1_OPTION:
+
+ /*
+ * The package count is variable, there are no sub-packages. There are
+ * a fixed number of required elements, and a variable number of
+ * optional elements.
+ *
+ * Check if package is at least as large as the minimum required
+ */
+ expected_count = package->ret_info3.count;
+ if (count < expected_count) {
+ goto package_too_small;
+ }
+
+ /* Variable number of sub-objects */
+
+ for (i = 0; i < count; i++) {
+ if (i < package->ret_info3.count) {
+
+ /* These are the required package elements (0, 1, or 2) */
+
+ status =
+ acpi_ns_check_object_type(pathname,
+ *elements,
+ package->
+ ret_info3.
+ object_type[i],
+ i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ } else {
+ /* These are the optional package elements */
+
+ status =
+ acpi_ns_check_object_type(pathname,
+ *elements,
+ package->
+ ret_info3.
+ tail_object_type,
+ i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+ elements++;
+ }
+ break;
+
+ case ACPI_PTYPE2_PKG_COUNT:
+
+ /* First element is the (Integer) count of sub-packages to follow */
+
+ status = acpi_ns_check_object_type(pathname, *elements,
+ ACPI_RTYPE_INTEGER, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /*
+ * Count cannot be larger than the parent package length, but allow it
+ * to be smaller. The >= accounts for the Integer above.
+ */
+ expected_count = (u32) (*elements)->integer.value;
+ if (expected_count >= count) {
+ goto package_too_small;
+ }
+
+ count = expected_count;
+ elements++;
+
+ /* Now we can walk the sub-packages */
+
+ /*lint -fallthrough */
+
+ case ACPI_PTYPE2:
+ case ACPI_PTYPE2_FIXED:
+ case ACPI_PTYPE2_MIN:
+ case ACPI_PTYPE2_COUNT:
+
+ /*
+ * These types all return a single package that consists of a variable
+ * number of sub-packages
+ */
+ for (i = 0; i < count; i++) {
+ sub_package = *elements;
+ sub_elements = sub_package->package.elements;
+
+ /* Each sub-object must be of type Package */
+
+ status =
+ acpi_ns_check_object_type(pathname, sub_package,
+ ACPI_RTYPE_PACKAGE, i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Examine the different types of sub-packages */
+
+ switch (package->ret_info.type) {
+ case ACPI_PTYPE2:
+ case ACPI_PTYPE2_PKG_COUNT:
+
+ /* Each subpackage has a fixed number of elements */
+
+ expected_count =
+ package->ret_info.count1 +
+ package->ret_info.count2;
+ if (sub_package->package.count !=
+ expected_count) {
+ count = sub_package->package.count;
+ goto package_too_small;
+ }
+
+ status =
+ acpi_ns_check_package_elements(pathname,
+ sub_elements,
+ package->
+ ret_info.
+ object_type1,
+ package->
+ ret_info.
+ count1,
+ package->
+ ret_info.
+ object_type2,
+ package->
+ ret_info.
+ count2);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_PTYPE2_FIXED:
+
+ /* Each sub-package has a fixed length */
+
+ expected_count = package->ret_info2.count;
+ if (sub_package->package.count < expected_count) {
+ count = sub_package->package.count;
+ goto package_too_small;
+ }
+
+ /* Check the type of each sub-package element */
+
+ for (j = 0; j < expected_count; j++) {
+ status =
+ acpi_ns_check_object_type(pathname,
+ sub_elements
+ [j],
+ package->
+ ret_info2.
+ object_type
+ [j], j);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+ break;
+
+ case ACPI_PTYPE2_MIN:
+
+ /* Each sub-package has a variable but minimum length */
+
+ expected_count = package->ret_info.count1;
+ if (sub_package->package.count < expected_count) {
+ count = sub_package->package.count;
+ goto package_too_small;
+ }
+
+ /* Check the type of each sub-package element */
+
+ status =
+ acpi_ns_check_package_elements(pathname,
+ sub_elements,
+ package->
+ ret_info.
+ object_type1,
+ sub_package->
+ package.
+ count, 0, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_PTYPE2_COUNT:
+
+ /* First element is the (Integer) count of elements to follow */
+
+ status =
+ acpi_ns_check_object_type(pathname,
+ *sub_elements,
+ ACPI_RTYPE_INTEGER,
+ 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Make sure package is large enough for the Count */
+
+ expected_count =
+ (u32) (*sub_elements)->integer.value;
+ if (sub_package->package.count < expected_count) {
+ count = sub_package->package.count;
+ goto package_too_small;
+ }
+
+ /* Check the type of each sub-package element */
+
+ status =
+ acpi_ns_check_package_elements(pathname,
+ (sub_elements
+ + 1),
+ package->
+ ret_info.
+ object_type1,
+ (expected_count
+ - 1), 0, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ elements++;
+ }
+ break;
+
+ default:
+
+ /* Should not get here if predefined info table is correct */
+
+ ACPI_WARNING((AE_INFO,
+ "%s: Invalid internal return type in table entry: %X",
+ pathname, package->ret_info.type));
+
+ return (AE_AML_INTERNAL);
+ }
+
+ return (AE_OK);
+
+ package_too_small:
+
+ /* Error exit for the case with an incorrect package count */
+
+ ACPI_WARNING((AE_INFO, "%s: Return Package is too small - "
+ "found %u, expected %u", pathname, count,
+ expected_count));
+
+ return (AE_AML_OPERAND_VALUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_package_elements
+ *
+ * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * Elements - Pointer to the package elements array
+ * Type1 - Object type for first group
+ * Count1 - Count for first group
+ * Type2 - Object type for second group
+ * Count2 - Count for second group
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check that all elements of a package are of the correct object
+ * type. Supports up to two groups of different object types.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_check_package_elements(char *pathname,
+ union acpi_operand_object **elements,
+ u8 type1, u32 count1, u8 type2, u32 count2)
+{
+ union acpi_operand_object **this_element = elements;
+ acpi_status status;
+ u32 i;
+
+ /*
+ * Up to two groups of package elements are supported by the data
+ * structure. All elements in each group must be of the same type.
+ * The second group can have a count of zero.
+ */
+ for (i = 0; i < count1; i++) {
+ status = acpi_ns_check_object_type(pathname, *this_element,
+ type1, i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ this_element++;
+ }
+
+ for (i = 0; i < count2; i++) {
+ status = acpi_ns_check_object_type(pathname, *this_element,
+ type2, (i + count1));
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ this_element++;
+ }
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * 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
+ * expected_btypes - Bitmap of expected return type(s)
+ * package_index - Index of object within parent package (if
+ * applicable - ACPI_NOT_PACKAGE otherwise)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check the type of the return object against the expected object
+ * type(s). Use of Btype allows multiple expected object types.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_check_object_type(char *pathname,
+ union acpi_operand_object *return_object,
+ u32 expected_btypes, u32 package_index)
+{
+ acpi_status status = AE_OK;
+ u32 return_btype;
+ char type_buffer[48]; /* Room for 5 types */
+ u32 this_rtype;
+ u32 i;
+ u32 j;
+
+ /*
+ * If we get a NULL return_object here, it is a NULL package element,
+ * and this is always an error.
+ */
+ if (!return_object) {
+ goto type_error_exit;
+ }
+
+ /* A Namespace node should not get here, but make sure */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) {
+ ACPI_WARNING((AE_INFO,
+ "%s: Invalid return type - Found a Namespace node [%4.4s] type %s",
+ pathname, return_object->node.name.ascii,
+ acpi_ut_get_type_name(return_object->node.type)));
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /*
+ * Convert the object type (ACPI_TYPE_xxx) to a bitmapped object type.
+ * The bitmapped type allows multiple possible return types.
+ *
+ * Note, the cases below must handle all of the possible types returned
+ * from all of the predefined names (including elements of returned
+ * packages)
+ */
+ switch (ACPI_GET_OBJECT_TYPE(return_object)) {
+ case ACPI_TYPE_INTEGER:
+ return_btype = ACPI_RTYPE_INTEGER;
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ return_btype = ACPI_RTYPE_BUFFER;
+ break;
+
+ case ACPI_TYPE_STRING:
+ return_btype = ACPI_RTYPE_STRING;
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ return_btype = ACPI_RTYPE_PACKAGE;
+ break;
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ return_btype = ACPI_RTYPE_REFERENCE;
+ break;
+
+ default:
+ /* Not one of the supported objects, must be incorrect */
+
+ goto type_error_exit;
+ }
+
+ /* Is the object one of the expected types? */
+
+ if (!(return_btype & expected_btypes)) {
+ goto type_error_exit;
+ }
+
+ /* For reference objects, check that the reference type is correct */
+
+ if (ACPI_GET_OBJECT_TYPE(return_object) == ACPI_TYPE_LOCAL_REFERENCE) {
+ status = acpi_ns_check_reference(pathname, return_object);
+ }
+
+ return (status);
+
+ type_error_exit:
+
+ /* Create a string with all expected types for this predefined object */
+
+ j = 1;
+ type_buffer[0] = 0;
+ this_rtype = ACPI_RTYPE_INTEGER;
+
+ for (i = 0; i < ACPI_NUM_RTYPES; i++) {
+
+ /* If one of the expected types, concatenate the name of this type */
+
+ if (expected_btypes & this_rtype) {
+ ACPI_STRCAT(type_buffer, &acpi_rtype_names[i][j]);
+ j = 0; /* Use name separator from now on */
+ }
+ this_rtype <<= 1; /* Next Rtype */
+ }
+
+ if (package_index == ACPI_NOT_PACKAGE) {
+ ACPI_WARNING((AE_INFO,
+ "%s: Return type mismatch - found %s, expected %s",
+ pathname,
+ acpi_ut_get_object_type_name(return_object),
+ type_buffer));
+ } else {
+ ACPI_WARNING((AE_INFO,
+ "%s: Return Package type mismatch at index %u - "
+ "found %s, expected %s", pathname, package_index,
+ acpi_ut_get_object_type_name(return_object),
+ type_buffer));
+ }
+
+ return (AE_AML_OPERAND_TYPE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_reference
+ *
+ * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * return_object - Object returned from the evaluation of a
+ * method or object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check a returned reference object for the correct reference
+ * type. The only reference type that can be returned from a
+ * predefined method is a named reference. All others are invalid.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_check_reference(char *pathname,
+ union acpi_operand_object *return_object)
+{
+
+ /*
+ * Check the reference object for the correct reference type (opcode).
+ * The only type of reference that can be converted to an union acpi_object is
+ * a reference to a named object (reference class: NAME)
+ */
+ if (return_object->reference.class == ACPI_REFCLASS_NAME) {
+ return (AE_OK);
+ }
+
+ ACPI_WARNING((AE_INFO,
+ "%s: Return type mismatch - unexpected reference object type [%s] %2.2X",
+ pathname, acpi_ut_get_reference_name(return_object),
+ return_object->reference.class));
+
+ return (AE_AML_OPERAND_TYPE);
+}
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index 8399276cba1..a9a80bf811b 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -331,7 +331,7 @@ acpi_ns_search_and_enter(u32 target_name,
"Found bad character(s) in name, repaired: [%4.4s]\n",
ACPI_CAST_PTR(char, &target_name)));
} else {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found bad character(s) in name, repaired: [%4.4s]\n",
ACPI_CAST_PTR(char, &target_name)));
}
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index 38be5865d95..a085cc39c05 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -48,6 +48,10 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsxfeval")
+
+/* Local prototypes */
+static void acpi_ns_resolve_references(struct acpi_evaluate_info *info);
+
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -69,6 +73,7 @@ ACPI_MODULE_NAME("nsxfeval")
* be valid (non-null)
*
******************************************************************************/
+
acpi_status
acpi_evaluate_object_typed(acpi_handle handle,
acpi_string pathname,
@@ -283,6 +288,10 @@ acpi_evaluate_object(acpi_handle handle,
if (ACPI_SUCCESS(status)) {
+ /* Dereference Index and ref_of references */
+
+ acpi_ns_resolve_references(info);
+
/* Get the size of the returned object */
status =
@@ -352,6 +361,74 @@ ACPI_EXPORT_SYMBOL(acpi_evaluate_object)
/*******************************************************************************
*
+ * FUNCTION: acpi_ns_resolve_references
+ *
+ * PARAMETERS: Info - Evaluation info block
+ *
+ * RETURN: Info->return_object is replaced with the dereferenced object
+ *
+ * DESCRIPTION: Dereference certain reference objects. Called before an
+ * internal return object is converted to an external union acpi_object.
+ *
+ * Performs an automatic dereference of Index and ref_of reference objects.
+ * These reference objects are not supported by the union acpi_object, so this is a
+ * last resort effort to return something useful. Also, provides compatibility
+ * with other ACPI implementations.
+ *
+ * NOTE: does not handle references within returned package objects or nested
+ * references, but this support could be added later if found to be necessary.
+ *
+ ******************************************************************************/
+static void acpi_ns_resolve_references(struct acpi_evaluate_info *info)
+{
+ union acpi_operand_object *obj_desc = NULL;
+ struct acpi_namespace_node *node;
+
+ /* We are interested in reference objects only */
+
+ if (ACPI_GET_OBJECT_TYPE(info->return_object) !=
+ ACPI_TYPE_LOCAL_REFERENCE) {
+ return;
+ }
+
+ /*
+ * Two types of references are supported - those created by Index and
+ * ref_of operators. A name reference (AML_NAMEPATH_OP) can be converted
+ * to an union acpi_object, so it is not dereferenced here. A ddb_handle
+ * (AML_LOAD_OP) cannot be dereferenced, nor can it be converted to
+ * an union acpi_object.
+ */
+ switch (info->return_object->reference.class) {
+ case ACPI_REFCLASS_INDEX:
+
+ obj_desc = *(info->return_object->reference.where);
+ break;
+
+ case ACPI_REFCLASS_REFOF:
+
+ node = info->return_object->reference.object;
+ if (node) {
+ obj_desc = node->object;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ /* Replace the existing reference object */
+
+ if (obj_desc) {
+ acpi_ut_add_reference(obj_desc);
+ acpi_ut_remove_reference(info->return_object);
+ info->return_object = obj_desc;
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_walk_namespace
*
* PARAMETERS: Type - acpi_object_type to search for
@@ -379,6 +456,7 @@ ACPI_EXPORT_SYMBOL(acpi_evaluate_object)
* function, etc.
*
******************************************************************************/
+
acpi_status
acpi_walk_namespace(acpi_object_type type,
acpi_handle start_object,
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index a287ed550f5..5efa4e7ddb0 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -253,6 +253,7 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
node = acpi_ns_map_handle_to_node(handle);
if (!node) {
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ status = AE_BAD_PARAMETER;
goto cleanup;
}
@@ -264,6 +265,10 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
info->name = node->name.integer;
info->valid = 0;
+ if (node->type == ACPI_TYPE_METHOD) {
+ info->param_count = node->object->method.param_count;
+ }
+
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
goto cleanup;
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index cb9864e39ba..25ceae9191e 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -258,7 +258,7 @@ int __init acpi_numa_init(void)
int acpi_get_pxm(acpi_handle h)
{
- unsigned long pxm;
+ unsigned long long pxm;
acpi_status status;
acpi_handle handle;
acpi_handle phandle = h;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 235a1386888..4be252145cb 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -608,7 +608,7 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */
acpi_handle handle;
struct acpi_pci_id *pci_id = *id;
acpi_status status;
- unsigned long temp;
+ unsigned long long temp;
acpi_object_type type;
acpi_get_parent(chandle, &handle);
@@ -620,8 +620,7 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */
if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
return;
- status =
- acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
+ status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
&temp);
if (ACPI_SUCCESS(status)) {
u32 val;
@@ -682,6 +681,22 @@ static void acpi_os_execute_deferred(struct work_struct *work)
return;
}
+static void acpi_os_execute_hp_deferred(struct work_struct *work)
+{
+ struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
+ if (!dpc) {
+ printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
+ return;
+ }
+
+ acpi_os_wait_events_complete(NULL);
+
+ dpc->function(dpc->context);
+ kfree(dpc);
+
+ return;
+}
+
/*******************************************************************************
*
* FUNCTION: acpi_os_execute
@@ -697,12 +712,13 @@ static void acpi_os_execute_deferred(struct work_struct *work)
*
******************************************************************************/
-acpi_status acpi_os_execute(acpi_execute_type type,
- acpi_osd_exec_callback function, void *context)
+static acpi_status __acpi_os_execute(acpi_execute_type type,
+ acpi_osd_exec_callback function, void *context, int hp)
{
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
struct workqueue_struct *queue;
+ int ret;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n",
function, context));
@@ -726,19 +742,38 @@ acpi_status acpi_os_execute(acpi_execute_type type,
dpc->function = function;
dpc->context = context;
- INIT_WORK(&dpc->work, acpi_os_execute_deferred);
- queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
- if (!queue_work(queue, &dpc->work)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Call to queue_work() failed.\n"));
+ if (!hp) {
+ INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+ queue = (type == OSL_NOTIFY_HANDLER) ?
+ kacpi_notify_wq : kacpid_wq;
+ ret = queue_work(queue, &dpc->work);
+ } else {
+ INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
+ ret = schedule_work(&dpc->work);
+ }
+
+ if (!ret) {
+ printk(KERN_ERR PREFIX
+ "Call to queue_work() failed.\n");
status = AE_ERROR;
kfree(dpc);
}
return_ACPI_STATUS(status);
}
+acpi_status acpi_os_execute(acpi_execute_type type,
+ acpi_osd_exec_callback function, void *context)
+{
+ return __acpi_os_execute(type, function, context, 0);
+}
EXPORT_SYMBOL(acpi_os_execute);
+acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
+ void *context)
+{
+ return __acpi_os_execute(0, function, context, 1);
+}
+
void acpi_os_wait_events_complete(void *context)
{
flush_workqueue(kacpid_wq);
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c
index c06238e55d9..4647039a0d8 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/parser/psloop.c
@@ -719,6 +719,8 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
*op = NULL;
}
+ ACPI_PREEMPTION_POINT();
+
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index 15e1702e48d..68e932f215e 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -137,6 +137,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
union acpi_parse_object *next;
const struct acpi_opcode_info *parent_info;
union acpi_parse_object *replacement_op = NULL;
+ acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op);
@@ -186,7 +187,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
replacement_op =
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
if (!replacement_op) {
- goto allocate_error;
+ status = AE_NO_MEMORY;
}
break;
@@ -211,7 +212,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
replacement_op =
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
if (!replacement_op) {
- goto allocate_error;
+ status = AE_NO_MEMORY;
}
} else
if ((op->common.parent->common.aml_opcode ==
@@ -226,13 +227,13 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
acpi_ps_alloc_op(op->common.
aml_opcode);
if (!replacement_op) {
- goto allocate_error;
+ status = AE_NO_MEMORY;
+ } else {
+ replacement_op->named.data =
+ op->named.data;
+ replacement_op->named.length =
+ op->named.length;
}
-
- replacement_op->named.data =
- op->named.data;
- replacement_op->named.length =
- op->named.length;
}
}
break;
@@ -242,7 +243,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
replacement_op =
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
if (!replacement_op) {
- goto allocate_error;
+ status = AE_NO_MEMORY;
}
}
@@ -302,14 +303,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
/* Now we can actually delete the subtree rooted at Op */
acpi_ps_delete_parse_tree(op);
- return_ACPI_STATUS(AE_OK);
-
- allocate_error:
-
- /* Always delete the subtree, even on error */
-
- acpi_ps_delete_parse_tree(op);
- return_ACPI_STATUS(AE_NO_MEMORY);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -641,10 +635,12 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
ACPI_WALK_METHOD_RESTART;
}
} else {
- /* On error, delete any return object */
+ /* On error, delete any return object or implicit return */
acpi_ut_remove_reference(previous_walk_state->
return_desc);
+ acpi_ds_clear_implicit_return
+ (previous_walk_state);
}
}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index cf47805a744..fcfdef7b4fd 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -709,7 +709,7 @@ int acpi_pci_link_free_irq(acpi_handle handle)
acpi_device_bid(link->device)));
if (link->refcnt == 0) {
- acpi_ut_evaluate_object(link->device->handle, "_DIS", 0, NULL);
+ acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
}
mutex_unlock(&acpi_link_lock);
return (link->irq.active);
@@ -737,7 +737,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
link->device = device;
strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
- acpi_driver_data(device) = link;
+ device->driver_data = link;
mutex_lock(&acpi_link_lock);
result = acpi_pci_link_get_possible(link);
@@ -773,7 +773,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
end:
/* disable all links -- to be activated on use */
- acpi_ut_evaluate_object(device->handle, "_DIS", 0, NULL);
+ acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
mutex_unlock(&acpi_link_lock);
if (result)
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index c3fed31166b..1b8f67d21d5 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -190,7 +190,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
struct acpi_pci_root *root = NULL;
struct acpi_pci_root *tmp;
acpi_status status = AE_OK;
- unsigned long value = 0;
+ unsigned long long value = 0;
acpi_handle handle = NULL;
struct acpi_device *child;
@@ -206,7 +206,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
root->device = device;
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
- acpi_driver_data(device) = root;
+ device->driver_data = root;
device->ops.bind = acpi_pci_bind;
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index d5b4ef89887..cd1f4467be7 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -76,10 +76,10 @@ static struct acpi_pci_driver acpi_pci_slot_driver = {
};
static int
-check_slot(acpi_handle handle, unsigned long *sun)
+check_slot(acpi_handle handle, unsigned long long *sun)
{
int device = -1;
- unsigned long adr, sta;
+ unsigned long long adr, sta;
acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -132,7 +132,7 @@ static acpi_status
register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
{
int device;
- unsigned long sun;
+ unsigned long long sun;
char name[SLOT_NAME_SIZE];
struct acpi_pci_slot *slot;
struct pci_slot *pci_slot;
@@ -150,7 +150,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
}
snprintf(name, sizeof(name), "%u", (u32)sun);
- pci_slot = pci_create_slot(pci_bus, device, name);
+ pci_slot = pci_create_slot(pci_bus, device, name, NULL);
if (IS_ERR(pci_slot)) {
err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
kfree(slot);
@@ -182,7 +182,7 @@ static acpi_status
walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
{
int device, function;
- unsigned long adr;
+ unsigned long long adr;
acpi_status status;
acpi_handle dummy_handle;
acpi_walk_callback user_function;
@@ -239,7 +239,7 @@ static int
walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function)
{
int seg, bus;
- unsigned long tmp;
+ unsigned long long tmp;
acpi_status status;
acpi_handle dummy_handle;
struct pci_bus *pci_bus;
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 4ab21cb1c8c..a1718e56103 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -54,6 +54,14 @@ ACPI_MODULE_NAME("power");
#define ACPI_POWER_RESOURCE_STATE_OFF 0x00
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
+
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "acpi."
+int acpi_power_nocheck;
+module_param_named(power_nocheck, acpi_power_nocheck, bool, 000);
+
static int acpi_power_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type);
static int acpi_power_resume(struct acpi_device *device);
@@ -128,16 +136,16 @@ acpi_power_get_context(acpi_handle handle,
return 0;
}
-static int acpi_power_get_state(struct acpi_power_resource *resource, int *state)
+static int acpi_power_get_state(acpi_handle handle, int *state)
{
acpi_status status = AE_OK;
- unsigned long sta = 0;
+ unsigned long long sta = 0;
- if (!resource || !state)
+ if (!handle || !state)
return -EINVAL;
- status = acpi_evaluate_integer(resource->device->handle, "_STA", NULL, &sta);
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -145,7 +153,7 @@ static int acpi_power_get_state(struct acpi_power_resource *resource, int *state
ACPI_POWER_RESOURCE_STATE_OFF;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
- resource->name, state ? "on" : "off"));
+ acpi_ut_get_node_name(handle), state ? "on" : "off"));
return 0;
}
@@ -153,7 +161,6 @@ static int acpi_power_get_state(struct acpi_power_resource *resource, int *state
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
{
int result = 0, state1;
- struct acpi_power_resource *resource = NULL;
u32 i = 0;
@@ -161,12 +168,15 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
return -EINVAL;
/* The state of the list is 'on' IFF all resources are 'on'. */
+ /* */
for (i = 0; i < list->count; i++) {
- result = acpi_power_get_context(list->handles[i], &resource);
- if (result)
- return result;
- result = acpi_power_get_state(resource, &state1);
+ /*
+ * The state of the power resource can be obtained by
+ * using the ACPI handle. In such case it is unnecessary to
+ * get the Power resource first and then get its state again.
+ */
+ result = acpi_power_get_state(list->handles[i], &state1);
if (result)
return result;
@@ -226,12 +236,18 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status))
return -ENODEV;
- result = acpi_power_get_state(resource, &state);
- if (result)
- return result;
- if (state != ACPI_POWER_RESOURCE_STATE_ON)
- return -ENOEXEC;
-
+ if (!acpi_power_nocheck) {
+ /*
+ * If acpi_power_nocheck is set, it is unnecessary to check
+ * the power state after power transition.
+ */
+ result = acpi_power_get_state(resource->device->handle,
+ &state);
+ if (result)
+ return result;
+ if (state != ACPI_POWER_RESOURCE_STATE_ON)
+ return -ENOEXEC;
+ }
/* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D0;
@@ -277,11 +293,17 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status))
return -ENODEV;
- result = acpi_power_get_state(resource, &state);
- if (result)
- return result;
- if (state != ACPI_POWER_RESOURCE_STATE_OFF)
- return -ENOEXEC;
+ if (!acpi_power_nocheck) {
+ /*
+ * If acpi_power_nocheck is set, it is unnecessary to check
+ * the power state after power transition.
+ */
+ result = acpi_power_get_state(handle, &state);
+ if (result)
+ return result;
+ if (state != ACPI_POWER_RESOURCE_STATE_OFF)
+ return -ENOEXEC;
+ }
/* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D3;
@@ -555,7 +577,7 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
if (!resource)
goto end;
- result = acpi_power_get_state(resource, &state);
+ result = acpi_power_get_state(resource->device->handle, &state);
if (result)
goto end;
@@ -657,7 +679,7 @@ static int acpi_power_add(struct acpi_device *device)
strcpy(resource->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
- acpi_driver_data(device) = resource;
+ device->driver_data = resource;
/* Evalute the object to get the system level and resource order. */
status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer);
@@ -668,7 +690,7 @@ static int acpi_power_add(struct acpi_device *device)
resource->system_level = acpi_object.power_resource.system_level;
resource->order = acpi_object.power_resource.resource_order;
- result = acpi_power_get_state(resource, &state);
+ result = acpi_power_get_state(device->handle, &state);
if (result)
goto end;
@@ -733,9 +755,9 @@ static int acpi_power_resume(struct acpi_device *device)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- resource = (struct acpi_power_resource *)acpi_driver_data(device);
+ resource = acpi_driver_data(device);
- result = acpi_power_get_state(resource, &state);
+ result = acpi_power_get_state(device->handle, &state);
if (result)
return result;
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index ee68ac54c0d..24a362f8034 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -563,7 +563,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
/* Check if it is a Device with HID and UID */
if (has_uid) {
- unsigned long value;
+ unsigned long long value;
status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
NULL, &value);
if (ACPI_FAILURE(status)) {
@@ -818,7 +818,7 @@ static int acpi_processor_add(struct acpi_device *device)
pr->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
- acpi_driver_data(device) = pr;
+ device->driver_data = pr;
return 0;
}
@@ -875,7 +875,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
static int is_processor_present(acpi_handle handle)
{
acpi_status status;
- unsigned long sta = 0;
+ unsigned long long sta = 0;
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index cf5b1b7b684..81b40ed5379 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1587,6 +1587,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
if (acpi_idle_bm_check()) {
if (dev->safe_state) {
+ dev->last_state = dev->safe_state;
return dev->safe_state->enter(dev, dev->safe_state);
} else {
local_irq_disable();
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 80c251ec6d2..dc98f7a6f2c 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -38,6 +38,7 @@
#include <asm/uaccess.h>
#endif
+#include <asm/cpufeature.h>
#include <acpi/acpi_bus.h>
#include <acpi/processor.h>
@@ -126,7 +127,7 @@ static struct notifier_block acpi_ppc_notifier_block = {
static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
{
acpi_status status = 0;
- unsigned long ppc = 0;
+ unsigned long long ppc = 0;
if (!pr)
@@ -334,7 +335,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
acpi_status status = AE_OK;
acpi_handle handle = NULL;
-
if (!pr || !pr->performance || !pr->handle)
return -EINVAL;
@@ -347,13 +347,25 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
result = acpi_processor_get_performance_control(pr);
if (result)
- return result;
+ goto update_bios;
result = acpi_processor_get_performance_states(pr);
if (result)
- return result;
+ goto update_bios;
return 0;
+
+ /*
+ * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that
+ * the BIOS is older than the CPU and does not know its frequencies
+ */
+ update_bios:
+ if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){
+ if(boot_cpu_has(X86_FEATURE_EST))
+ printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
+ "frequency support\n");
+ }
+ return result;
}
int acpi_processor_notify_smm(struct module *calling_module)
@@ -524,13 +536,13 @@ static int acpi_processor_get_psd(struct acpi_processor *pr)
psd = buffer.pointer;
if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
+ printk(KERN_ERR PREFIX "Invalid _PSD data\n");
result = -EFAULT;
goto end;
}
if (psd->package.count != 1) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
+ printk(KERN_ERR PREFIX "Invalid _PSD data\n");
result = -EFAULT;
goto end;
}
@@ -543,19 +555,19 @@ static int acpi_processor_get_psd(struct acpi_processor *pr)
status = acpi_extract_package(&(psd->package.elements[0]),
&format, &state);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
+ printk(KERN_ERR PREFIX "Invalid _PSD data\n");
result = -EFAULT;
goto end;
}
if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n"));
+ printk(KERN_ERR PREFIX "Unknown _PSD:num_entries\n");
result = -EFAULT;
goto end;
}
if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n"));
+ printk(KERN_ERR PREFIX "Unknown _PSD:revision\n");
result = -EFAULT;
goto end;
}
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index a56fc6c4394..3da2df93d92 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -274,7 +274,7 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data)
static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
{
acpi_status status = 0;
- unsigned long tpc = 0;
+ unsigned long long tpc = 0;
if (!pr)
return -EINVAL;
@@ -528,13 +528,13 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
tsd = buffer.pointer;
if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+ printk(KERN_ERR PREFIX "Invalid _TSD data\n");
result = -EFAULT;
goto end;
}
if (tsd->package.count != 1) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+ printk(KERN_ERR PREFIX "Invalid _TSD data\n");
result = -EFAULT;
goto end;
}
@@ -547,19 +547,19 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
status = acpi_extract_package(&(tsd->package.elements[0]),
&format, &state);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+ printk(KERN_ERR PREFIX "Invalid _TSD data\n");
result = -EFAULT;
goto end;
}
if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n"));
+ printk(KERN_ERR PREFIX "Unknown _TSD:num_entries\n");
result = -EFAULT;
goto end;
}
if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n"));
+ printk(KERN_ERR PREFIX "Unknown _TSD:revision\n");
result = -EFAULT;
goto end;
}
diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c
index a6b662c00b6..755baf2ca70 100644
--- a/drivers/acpi/reboot.c
+++ b/drivers/acpi/reboot.c
@@ -15,9 +15,28 @@ void acpi_reboot(void)
rr = &acpi_gbl_FADT.reset_register;
- /* Is the reset register supported? */
- if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) ||
- rr->bit_width != 8 || rr->bit_offset != 0)
+ /*
+ * Is the ACPI reset register supported?
+ *
+ * According to ACPI 3.0, FADT.flags.RESET_REG_SUP indicates
+ * whether the ACPI reset mechanism is supported.
+ *
+ * However, some boxes have this bit clear, yet a valid
+ * ACPI_RESET_REG & RESET_VALUE, and ACPI reboot is the only
+ * mechanism that works for them after S3.
+ *
+ * This suggests that other operating systems may not be checking
+ * the RESET_REG_SUP bit, and are using other means to decide
+ * whether to use the ACPI reboot mechanism or not.
+ *
+ * So when acpi reboot is requested,
+ * only the reset_register is checked. If the following
+ * conditions are met, it indicates that the reset register is supported.
+ * a. reset_register is not zero
+ * b. the access width is eight
+ * c. the bit_offset is zero
+ */
+ if (!(rr->address) || rr->bit_width != 8 || rr->bit_offset != 0)
return;
reset_value = acpi_gbl_FADT.reset_value;
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index d9063ea414e..8eaaecf9200 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -43,7 +43,6 @@
#include <acpi/acpi.h>
#include <acpi/acresrc.h>
-#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
#define _COMPONENT ACPI_RESOURCES
@@ -560,8 +559,8 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
ACPI_GET_OBJECT_TYPE(*sub_object_list)) ||
((ACPI_TYPE_LOCAL_REFERENCE ==
ACPI_GET_OBJECT_TYPE(*sub_object_list)) &&
- ((*sub_object_list)->reference.opcode ==
- AML_INT_NAMEPATH_OP)))) {
+ ((*sub_object_list)->reference.class ==
+ ACPI_REFCLASS_NAME)))) {
name_found = TRUE;
} else {
/* Look at the next element */
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index 7804a8c40e7..c0bbfa2c419 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -43,7 +43,6 @@
#include <acpi/acpi.h>
#include <acpi/acresrc.h>
-#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
#define _COMPONENT ACPI_RESOURCES
@@ -310,13 +309,12 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE:
- if (obj_desc->reference.opcode !=
- AML_INT_NAMEPATH_OP) {
+ if (obj_desc->reference.class !=
+ ACPI_REFCLASS_NAME) {
ACPI_ERROR((AE_INFO,
- "(PRT[%X].Source) Need name, found reference op %X",
+ "(PRT[%X].Source) Need name, found Reference Class %X",
index,
- obj_desc->reference.
- opcode));
+ obj_desc->reference.class));
return_ACPI_STATUS(AE_BAD_DATA);
}
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 10a36512647..6050ce48187 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -463,7 +463,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev,
}
static struct device_attribute alarm_attr = {
- .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
+ .attr = {.name = "alarm", .mode = 0644},
.show = acpi_battery_alarm_show,
.store = acpi_battery_alarm_store,
};
@@ -931,7 +931,7 @@ static int acpi_sbs_add(struct acpi_device *device)
sbs->device = device;
strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
- acpi_driver_data(device) = sbs;
+ device->driver_data = sbs;
result = acpi_charger_add(sbs);
if (result)
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index a4e3767b8c6..e53e590252c 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -258,7 +258,7 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
static int acpi_smbus_hc_add(struct acpi_device *device)
{
int status;
- unsigned long val;
+ unsigned long long val;
struct acpi_smb_hc *hc;
if (!device)
@@ -282,7 +282,7 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
hc->ec = acpi_driver_data(device->parent);
hc->offset = (val >> 8) & 0xff;
hc->query_bit = val & 0xff;
- acpi_driver_data(device) = hc;
+ device->driver_data = hc;
acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
@@ -303,7 +303,7 @@ static int acpi_smbus_hc_remove(struct acpi_device *device, int type)
hc = acpi_driver_data(device);
acpi_ec_remove_query_handler(hc->ec, hc->query_bit);
kfree(hc);
- acpi_driver_data(device) = NULL;
+ device->driver_data = NULL;
return 0;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index f6f52c1a2ab..a9dda8e0f9f 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -113,16 +113,16 @@ static int acpi_bus_hot_remove_device(void *context)
if (acpi_bus_trim(device, 1)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Removing device failed\n"));
+ printk(KERN_ERR PREFIX
+ "Removing device failed\n");
return -1;
}
/* power off device */
status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Power-off device failed\n"));
+ printk(KERN_WARNING PREFIX
+ "Power-off device failed\n");
if (device->flags.lockable) {
arg_list.count = 1;
@@ -276,6 +276,13 @@ int acpi_match_device_ids(struct acpi_device *device,
{
const struct acpi_device_id *id;
+ /*
+ * If the device is not present, it is unnecessary to load device
+ * driver for it.
+ */
+ if (!device->status.present)
+ return -ENODEV;
+
if (device->flags.hardware_id) {
for (id = ids; id->id[0]; id++) {
if (!strcmp((char*)id->id, device->pnp.hardware_id))
@@ -384,7 +391,7 @@ static int acpi_device_remove(struct device * dev)
acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
}
acpi_dev->driver = NULL;
- acpi_driver_data(dev) = NULL;
+ acpi_dev->driver_data = NULL;
put_device(dev);
return 0;
@@ -477,7 +484,7 @@ static int acpi_device_register(struct acpi_device *device,
result = acpi_device_setup_files(device);
if(result)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
+ printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n", device->dev.bus_id);
device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
return 0;
@@ -537,7 +544,7 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
result = driver->ops.add(device);
if (result) {
device->driver = NULL;
- acpi_driver_data(device) = NULL;
+ device->driver_data = NULL;
return result;
}
@@ -744,6 +751,16 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1;
+ /*
+ * Don't set Power button GPE as run_wake
+ * if Fixed Power button is used
+ */
+ if (!strcmp(device->pnp.hardware_id, "PNP0C0C") &&
+ !(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) {
+ device->wakeup.flags.run_wake = 0;
+ device->wakeup.flags.valid = 0;
+ }
+
end:
if (ACPI_FAILURE(status))
device->flags.wake_capable = 0;
@@ -807,6 +824,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
/* TBD: System wake support and resource requirements. */
device->power.state = ACPI_STATE_UNKNOWN;
+ acpi_bus_get_power(device->handle, &(device->power.state));
return 0;
}
@@ -1153,20 +1171,6 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
}
static int
-acpi_is_child_device(struct acpi_device *device,
- int (*matcher)(struct acpi_device *))
-{
- int result = -ENODEV;
-
- do {
- if (ACPI_SUCCESS(matcher(device)))
- return AE_OK;
- } while ((device = device->parent));
-
- return result;
-}
-
-static int
acpi_add_single_object(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type,
struct acpi_bus_ops *ops)
@@ -1221,15 +1225,18 @@ acpi_add_single_object(struct acpi_device **child,
result = -ENODEV;
goto end;
}
- if (!device->status.present) {
- /* Bay and dock should be handled even if absent */
- if (!ACPI_SUCCESS(
- acpi_is_child_device(device, acpi_bay_match)) &&
- !ACPI_SUCCESS(
- acpi_is_child_device(device, acpi_dock_match))) {
- result = -ENODEV;
- goto end;
- }
+ /*
+ * When the device is neither present nor functional, the
+ * device should not be added to Linux ACPI device tree.
+ * When the status of the device is not present but functinal,
+ * it should be added to Linux ACPI tree. For example : bay
+ * device , dock device.
+ * In such conditions it is unncessary to check whether it is
+ * bay device or dock device.
+ */
+ if (!device->status.present && !device->status.functional) {
+ result = -ENODEV;
+ goto end;
}
break;
default:
@@ -1252,6 +1259,16 @@ acpi_add_single_object(struct acpi_device **child,
acpi_device_set_id(device, parent, handle, type);
/*
+ * The ACPI device is attached to acpi handle before getting
+ * the power/wakeup/peformance flags. Otherwise OS can't get
+ * the corresponding ACPI device by the acpi handle in the course
+ * of getting the power/wakeup/performance flags.
+ */
+ result = acpi_device_set_context(device, type);
+ if (result)
+ goto end;
+
+ /*
* Power Management
* ----------------
*/
@@ -1281,8 +1298,6 @@ acpi_add_single_object(struct acpi_device **child,
goto end;
}
- if ((result = acpi_device_set_context(device, type)))
- goto end;
result = acpi_device_register(device, parent);
@@ -1402,7 +1417,12 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
* TBD: Need notifications and other detection mechanisms
* in place before we can fully implement this.
*/
- if (child->status.present) {
+ /*
+ * When the device is not present but functional, it is also
+ * necessary to scan the children of this device.
+ */
+ if (child->status.present || (!child->status.present &&
+ child->status.functional)) {
status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
NULL, NULL);
if (ACPI_SUCCESS(status)) {
@@ -1545,7 +1565,6 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
return result;
}
-int __init acpi_boot_ec_enable(void);
static int __init acpi_scan_init(void)
{
@@ -1579,9 +1598,6 @@ static int __init acpi_scan_init(void)
*/
result = acpi_bus_scan_fixed(acpi_root);
- /* EC region might be needed at bus_scan, so enable it now */
- acpi_boot_ec_enable();
-
if (!result)
result = acpi_bus_scan(acpi_root, &ops);
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index d13194a031b..26571bafb15 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -15,6 +15,7 @@
#include <linux/dmi.h>
#include <linux/device.h>
#include <linux/suspend.h>
+#include <linux/reboot.h>
#include <asm/io.h>
@@ -24,6 +25,36 @@
u8 sleep_states[ACPI_S_STATE_COUNT];
+static void acpi_sleep_tts_switch(u32 acpi_state)
+{
+ union acpi_object in_arg = { ACPI_TYPE_INTEGER };
+ struct acpi_object_list arg_list = { 1, &in_arg };
+ acpi_status status = AE_OK;
+
+ in_arg.integer.value = acpi_state;
+ status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ /*
+ * OS can't evaluate the _TTS object correctly. Some warning
+ * message will be printed. But it won't break anything.
+ */
+ printk(KERN_NOTICE "Failure in evaluating _TTS object\n");
+ }
+}
+
+static int tts_notify_reboot(struct notifier_block *this,
+ unsigned long code, void *x)
+{
+ acpi_sleep_tts_switch(ACPI_STATE_S5);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block tts_notifier = {
+ .notifier_call = tts_notify_reboot,
+ .next = NULL,
+ .priority = 0,
+};
+
static int acpi_sleep_prepare(u32 acpi_state)
{
#ifdef CONFIG_ACPI_SLEEP
@@ -45,9 +76,8 @@ static int acpi_sleep_prepare(u32 acpi_state)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ACPI_SLEEP
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
-
/*
* ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
* user to request that behavior by using the 'acpi_old_suspend_ordering'
@@ -131,8 +161,9 @@ static void acpi_pm_end(void)
* failing transition to a sleep state.
*/
acpi_target_sleep_state = ACPI_STATE_S0;
+ acpi_sleep_tts_switch(acpi_target_sleep_state);
}
-#endif /* CONFIG_PM_SLEEP */
+#endif /* CONFIG_ACPI_SLEEP */
#ifdef CONFIG_SUSPEND
extern void do_suspend_lowlevel(void);
@@ -155,6 +186,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
if (sleep_states[acpi_state]) {
acpi_target_sleep_state = acpi_state;
+ acpi_sleep_tts_switch(acpi_target_sleep_state);
} else {
printk(KERN_ERR "ACPI does not support this state: %d\n",
pm_state);
@@ -200,6 +232,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
break;
}
+ /* If ACPI is not enabled by the BIOS, we need to enable it here. */
+ acpi_enable();
/* Reprogram control registers and execute _BFS */
acpi_leave_sleep_state_prep(acpi_state);
@@ -296,6 +330,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"),
},
},
+ {
+ .callback = init_old_suspend_ordering,
+ .ident = "HP xw4600 Workstation",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"),
+ },
+ },
{},
};
#endif /* CONFIG_SUSPEND */
@@ -313,6 +355,7 @@ 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;
}
@@ -376,7 +419,15 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
*/
static int acpi_hibernation_begin_old(void)
{
- int error = acpi_sleep_prepare(ACPI_STATE_S4);
+ int error;
+ /*
+ * The _TTS object should always be evaluated before the _PTS object.
+ * When the old_suspended_ordering is true, the _PTS object is
+ * evaluated in the acpi_sleep_prepare.
+ */
+ acpi_sleep_tts_switch(ACPI_STATE_S4);
+
+ error = acpi_sleep_prepare(ACPI_STATE_S4);
if (!error)
acpi_target_sleep_state = ACPI_STATE_S4;
@@ -444,7 +495,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
struct acpi_device *adev;
char acpi_method[] = "_SxD";
- unsigned long d_min, d_max;
+ unsigned long long d_min, d_max;
if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
printk(KERN_DEBUG "ACPI handle has no context!\n");
@@ -596,5 +647,10 @@ int __init acpi_sleep_init(void)
pm_power_off = acpi_power_off;
}
printk(")\n");
+ /*
+ * Register the tts_notifier to reboot notifier list so that the _TTS
+ * object can also be evaluated when the system enters S5.
+ */
+ register_reboot_notifier(&tts_notifier);
return 0;
}
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index bf5b04de02d..631ee2ee2ca 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -120,13 +120,13 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
spin_unlock_irqrestore(&rtc_lock, flags);
if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hr);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mo);
- BCD_TO_BIN(yr);
- BCD_TO_BIN(cent);
+ 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) */
@@ -204,7 +204,7 @@ static u32 cmos_bcd_read(int offset, int rtc_control)
{
u32 val = CMOS_READ(offset);
if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- BCD_TO_BIN(val);
+ val = bcd2bin(val);
return val;
}
@@ -212,7 +212,7 @@ static u32 cmos_bcd_read(int offset, int rtc_control)
static void cmos_bcd_write(u32 val, int offset, int rtc_control)
{
if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- BIN_TO_BCD(val);
+ val = bin2bcd(val);
CMOS_WRITE(val, offset);
}
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 91dec448b3e..1d74171b794 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -115,7 +115,6 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
table_attr->attr.read = acpi_table_show;
table_attr->attr.attr.name = table_attr->name;
table_attr->attr.attr.mode = 0444;
- table_attr->attr.attr.owner = THIS_MODULE;
return;
}
@@ -387,8 +386,8 @@ static ssize_t counter_set(struct kobject *kobj,
goto end;
if (!(all_counters[index].flags & ACPI_EVENT_VALID)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Can not change Invalid GPE/Fixed Event status\n"));
+ printk(KERN_WARNING PREFIX
+ "Can not change Invalid GPE/Fixed Event status\n");
return -EINVAL;
}
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index a4a41ba2484..2c7885e7ffb 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -50,7 +50,7 @@ ACPI_MODULE_NAME("tbfadt")
/* Local prototypes */
static void inline
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
- u8 bit_width, u64 address);
+ u8 byte_width, u64 address);
static void acpi_tb_convert_fadt(void);
@@ -111,7 +111,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
* FUNCTION: acpi_tb_init_generic_address
*
* PARAMETERS: generic_address - GAS struct to be initialized
- * bit_width - Width of this register
+ * byte_width - Width of this register
* Address - Address of the register
*
* RETURN: None
@@ -124,7 +124,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
static void inline
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
- u8 bit_width, u64 address)
+ u8 byte_width, u64 address)
{
/*
@@ -136,7 +136,7 @@ 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 = bit_width;
+ generic_address->bit_width = byte_width << 3;
generic_address->bit_offset = 0;
generic_address->access_width = 0;
}
@@ -342,9 +342,20 @@ static void acpi_tb_convert_fadt(void)
* useful to calculate them once, here.
*
* The PM event blocks are split into two register blocks, first is the
- * PM Status Register block, followed immediately by the PM Enable Register
- * block. Each is of length (pm1_event_length/2)
+ * PM Status Register block, followed immediately by the PM Enable
+ * Register block. Each is of length (xpm1x_event_block.bit_width/2).
+ *
+ * On various systems the v2 fields (and particularly the bit widths)
+ * cannot be relied upon, though. Hence resort to using the v1 length
+ * here (and warn about the inconsistency).
*/
+ if (acpi_gbl_FADT.xpm1a_event_block.bit_width
+ != acpi_gbl_FADT.pm1_event_length * 8)
+ printk(KERN_WARNING "FADT: "
+ "X_PM1a_EVT_BLK.bit_width (%u) does not match"
+ " 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 */
@@ -360,13 +371,20 @@ static void acpi_tb_convert_fadt(void)
/* The PM1B register block is optional, ignore if not present */
if (acpi_gbl_FADT.xpm1b_event_block.address) {
+ if (acpi_gbl_FADT.xpm1b_event_block.bit_width
+ != acpi_gbl_FADT.pm1_event_length * 8)
+ printk(KERN_WARNING "FADT: "
+ "X_PM1b_EVT_BLK.bit_width (%u) does not match"
+ " PM1_EVT_LEN (%u)\n",
+ 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.
address + pm1_register_length));
/* Don't forget to copy space_id of the GAS */
acpi_gbl_xpm1b_enable.space_id =
- acpi_gbl_FADT.xpm1a_event_block.space_id;
+ acpi_gbl_FADT.xpm1b_event_block.space_id;
}
}
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index b22185f55a1..18747ce8dd2 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -110,7 +110,6 @@ acpi_status
acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
{
u32 i;
- u32 length;
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(tb_add_table);
@@ -145,25 +144,64 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
}
}
- length = ACPI_MIN(table_desc->length,
- acpi_gbl_root_table_list.tables[i].length);
+ /*
+ * Check for a table match on the entire table length,
+ * not just the header.
+ */
+ if (table_desc->length !=
+ acpi_gbl_root_table_list.tables[i].length) {
+ continue;
+ }
+
if (ACPI_MEMCMP(table_desc->pointer,
acpi_gbl_root_table_list.tables[i].pointer,
- length)) {
+ acpi_gbl_root_table_list.tables[i].length)) {
continue;
}
- /* Table is already registered */
-
+ /*
+ * Note: the current mechanism does not unregister a table if it is
+ * dynamically unloaded. The related namespace entries are deleted,
+ * but the table remains in the root table list.
+ *
+ * The assumption here is that the number of different tables that
+ * will be loaded is actually small, and there is minimal overhead
+ * in just keeping the table in case it is needed again.
+ *
+ * If this assumption changes in the future (perhaps on large
+ * machines with many table load/unload operations), tables will
+ * need to be unregistered when they are unloaded, and slots in the
+ * root table list should be reused when empty.
+ */
+
+ /*
+ * Table is already registered.
+ * We can delete the table that was passed as a parameter.
+ */
acpi_tb_delete_table(table_desc);
*table_index = i;
- status = AE_ALREADY_EXISTS;
- goto release;
+
+ if (acpi_gbl_root_table_list.tables[i].
+ flags & ACPI_TABLE_IS_LOADED) {
+
+ /* Table is still loaded, this is an error */
+
+ status = AE_ALREADY_EXISTS;
+ goto release;
+ } else {
+ /* Table was unloaded, allow it to be reloaded */
+
+ table_desc->pointer =
+ acpi_gbl_root_table_list.tables[i].pointer;
+ table_desc->address =
+ acpi_gbl_root_table_list.tables[i].address;
+ status = AE_OK;
+ goto print_header;
+ }
}
- /*
- * Add the table to the global table list
- */
+ /* Add the table to the global root table list */
+
status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
table_desc->length, table_desc->flags,
table_index);
@@ -171,6 +209,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
goto release;
}
+ print_header:
acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
release:
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 912703691d3..ad6cae938f0 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -246,18 +246,18 @@ static const struct file_operations acpi_thermal_polling_fops = {
static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
{
acpi_status status = AE_OK;
-
+ unsigned long long tmp;
if (!tz)
return -EINVAL;
tz->last_temperature = tz->temperature;
- status =
- acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tz->temperature);
+ status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
if (ACPI_FAILURE(status))
return -ENODEV;
+ tz->temperature = tmp;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
tz->temperature));
@@ -267,17 +267,16 @@ static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
{
acpi_status status = AE_OK;
-
+ unsigned long long tmp;
if (!tz)
return -EINVAL;
- status =
- acpi_evaluate_integer(tz->device->handle, "_TZP", NULL,
- &tz->polling_frequency);
+ status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
if (ACPI_FAILURE(status))
return -ENODEV;
+ tz->polling_frequency = tmp;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
tz->polling_frequency));
@@ -356,6 +355,7 @@ do { \
static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
{
acpi_status status = AE_OK;
+ unsigned long long tmp;
struct acpi_handle_list devices;
int valid = 0;
int i;
@@ -363,7 +363,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
/* Critical Shutdown (required) */
if (flag & ACPI_TRIPS_CRITICAL) {
status = acpi_evaluate_integer(tz->device->handle,
- "_CRT", NULL, &tz->trips.critical.temperature);
+ "_CRT", NULL, &tmp);
+ tz->trips.critical.temperature = tmp;
/*
* Treat freezing temperatures as invalid as well; some
* BIOSes return really low values and cause reboots at startup.
@@ -388,10 +389,12 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
} else if (crt > 0) {
unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
/*
- * Allow override to lower critical threshold
+ * Allow override critical threshold
*/
- if (crt_k < tz->trips.critical.temperature)
- tz->trips.critical.temperature = crt_k;
+ if (crt_k > tz->trips.critical.temperature)
+ printk(KERN_WARNING PREFIX
+ "Critical threshold %d C\n", crt);
+ tz->trips.critical.temperature = crt_k;
}
}
}
@@ -399,12 +402,13 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
/* Critical Sleep (optional) */
if (flag & ACPI_TRIPS_HOT) {
status = acpi_evaluate_integer(tz->device->handle,
- "_HOT", NULL, &tz->trips.hot.temperature);
+ "_HOT", NULL, &tmp);
if (ACPI_FAILURE(status)) {
tz->trips.hot.flags.valid = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No hot threshold\n"));
} else {
+ tz->trips.hot.temperature = tmp;
tz->trips.hot.flags.valid = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found hot threshold [%lu]\n",
@@ -418,33 +422,40 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
if (psv == -1) {
status = AE_SUPPORT;
} else if (psv > 0) {
- tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
+ tmp = CELSIUS_TO_KELVIN(psv);
status = AE_OK;
} else {
status = acpi_evaluate_integer(tz->device->handle,
- "_PSV", NULL, &tz->trips.passive.temperature);
+ "_PSV", NULL, &tmp);
}
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
else {
+ tz->trips.passive.temperature = tmp;
tz->trips.passive.flags.valid = 1;
if (flag == ACPI_TRIPS_INIT) {
status = acpi_evaluate_integer(
tz->device->handle, "_TC1",
- NULL, &tz->trips.passive.tc1);
+ NULL, &tmp);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
+ else
+ tz->trips.passive.tc1 = tmp;
status = acpi_evaluate_integer(
tz->device->handle, "_TC2",
- NULL, &tz->trips.passive.tc2);
+ NULL, &tmp);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
+ else
+ tz->trips.passive.tc2 = tmp;
status = acpi_evaluate_integer(
tz->device->handle, "_TSP",
- NULL, &tz->trips.passive.tsp);
+ NULL, &tmp);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
+ else
+ tz->trips.passive.tsp = tmp;
}
}
}
@@ -479,7 +490,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
if (flag & ACPI_TRIPS_ACTIVE) {
status = acpi_evaluate_integer(tz->device->handle,
- name, NULL, &tz->trips.active[i].temperature);
+ name, NULL, &tmp);
if (ACPI_FAILURE(status)) {
tz->trips.active[i].flags.valid = 0;
if (i == 0)
@@ -500,8 +511,10 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
tz->trips.active[i - 2].temperature :
CELSIUS_TO_KELVIN(act));
break;
- } else
+ } else {
+ tz->trips.active[i].temperature = tmp;
tz->trips.active[i].flags.valid = 1;
+ }
}
name[2] = 'L';
@@ -1213,8 +1226,8 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
acpi_bus_private_data_handler,
tz->thermal_zone);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error attaching device data\n"));
+ printk(KERN_ERR PREFIX
+ "Error attaching device data\n");
return -ENODEV;
}
@@ -1647,7 +1660,7 @@ static int acpi_thermal_add(struct acpi_device *device)
strcpy(tz->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
- acpi_driver_data(device) = tz;
+ device->driver_data = tz;
mutex_init(&tz->lock);
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index 8a649f40d16..2a632f8b7a0 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -548,7 +548,7 @@ static unsigned long write_video(const char *buffer, unsigned long count)
hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
if (hci_result == HCI_SUCCESS) {
- int new_video_out = video_out;
+ unsigned int new_video_out = video_out;
if (lcd_out != -1)
_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
if (crt_out != -1)
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index 7dcb67e0b21..241c535c175 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -232,7 +232,7 @@ acpi_status acpi_ut_validate_buffer(struct acpi_buffer * buffer)
* RETURN: Status
*
* DESCRIPTION: Validate that the buffer is of the required length or
- * allocate a new buffer. Returned buffer is always zeroed.
+ * allocate a new buffer. Returned buffer is always zeroed.
*
******************************************************************************/
@@ -240,7 +240,7 @@ acpi_status
acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
acpi_size required_length)
{
- acpi_status status = AE_OK;
+ acpi_size input_buffer_length;
/* Parameter validation */
@@ -248,55 +248,58 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
return (AE_BAD_PARAMETER);
}
- switch (buffer->length) {
+ /*
+ * Buffer->Length is used as both an input and output parameter. Get the
+ * input actual length and set the output required buffer length.
+ */
+ input_buffer_length = buffer->length;
+ buffer->length = required_length;
+
+ /*
+ * The input buffer length contains the actual buffer length, or the type
+ * of buffer to be allocated by this routine.
+ */
+ switch (input_buffer_length) {
case ACPI_NO_BUFFER:
- /* Set the exception and returned the required length */
+ /* Return the exception (and the required buffer length) */
- status = AE_BUFFER_OVERFLOW;
- break;
+ return (AE_BUFFER_OVERFLOW);
case ACPI_ALLOCATE_BUFFER:
/* Allocate a new buffer */
buffer->pointer = acpi_os_allocate(required_length);
- if (!buffer->pointer) {
- return (AE_NO_MEMORY);
- }
-
- /* Clear the buffer */
-
- ACPI_MEMSET(buffer->pointer, 0, required_length);
break;
case ACPI_ALLOCATE_LOCAL_BUFFER:
/* Allocate a new buffer with local interface to allow tracking */
- buffer->pointer = ACPI_ALLOCATE_ZEROED(required_length);
- if (!buffer->pointer) {
- return (AE_NO_MEMORY);
- }
+ buffer->pointer = ACPI_ALLOCATE(required_length);
break;
default:
/* Existing buffer: Validate the size of the buffer */
- if (buffer->length < required_length) {
- status = AE_BUFFER_OVERFLOW;
- break;
+ if (input_buffer_length < required_length) {
+ return (AE_BUFFER_OVERFLOW);
}
+ break;
+ }
- /* Clear the buffer */
+ /* Validate allocation from above or input buffer pointer */
- ACPI_MEMSET(buffer->pointer, 0, required_length);
- break;
+ if (!buffer->pointer) {
+ return (AE_NO_MEMORY);
}
- buffer->length = required_length;
- return (status);
+ /* Have a valid buffer, clear it */
+
+ ACPI_MEMSET(buffer->pointer, 0, required_length);
+ return (AE_OK);
}
#ifdef NOT_USED_BY_LINUX
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 53499ac9098..5b2f7c27b70 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -42,7 +42,6 @@
*/
#include <acpi/acpi.h>
-#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
@@ -176,20 +175,24 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object,
/* This is an object reference. */
- switch (internal_object->reference.opcode) {
- case AML_INT_NAMEPATH_OP:
-
- /* For namepath, return the object handle ("reference") */
-
- default:
-
- /* We are referring to the namespace node */
+ switch (internal_object->reference.class) {
+ case ACPI_REFCLASS_NAME:
+ /*
+ * For namepath, return the object handle ("reference")
+ * We are referring to the namespace node
+ */
external_object->reference.handle =
internal_object->reference.node;
external_object->reference.actual_type =
acpi_ns_get_type(internal_object->reference.node);
break;
+
+ default:
+
+ /* All other reference types are unsupported */
+
+ return_ACPI_STATUS(AE_TYPE);
}
break;
@@ -533,7 +536,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
/* TBD: should validate incoming handle */
- internal_object->reference.opcode = AML_INT_NAMEPATH_OP;
+ internal_object->reference.class = ACPI_REFCLASS_NAME;
internal_object->reference.node =
external_object->reference.handle;
break;
@@ -743,11 +746,11 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
* We copied the reference object, so we now must add a reference
* to the object pointed to by the reference
*
- * DDBHandle reference (from Load/load_table is a special reference,
- * it's Reference.Object is the table index, so does not need to
+ * DDBHandle reference (from Load/load_table) is a special reference,
+ * it does not have a Reference.Object, so does not need to
* increase the reference count
*/
- if (source_desc->reference.opcode == AML_LOAD_OP) {
+ if (source_desc->reference.class == ACPI_REFCLASS_TABLE) {
break;
}
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 42609d3a8aa..d197c6b29e1 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -45,7 +45,6 @@
#include <acpi/acinterp.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
-#include <acpi/amlcode.h>
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utdelete")
@@ -548,8 +547,8 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
* reference must track changes to the ref count of the index or
* target object.
*/
- if ((object->reference.opcode == AML_INDEX_OP) ||
- (object->reference.opcode == AML_INT_NAMEPATH_OP)) {
+ if ((object->reference.class == ACPI_REFCLASS_INDEX) ||
+ (object->reference.class == ACPI_REFCLASS_NAME)) {
next_object = object->reference.object;
}
break;
@@ -586,6 +585,13 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
ACPI_EXCEPTION((AE_INFO, status,
"Could not update object reference count"));
+ /* Free any stacked Update State objects */
+
+ while (state_list) {
+ state = acpi_ut_pop_generic_state(&state_list);
+ acpi_ut_delete_generic_state(state);
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index a6e71b801d2..670551b95e5 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -281,7 +281,6 @@ struct acpi_bit_register_info acpi_gbl_bit_register_info[ACPI_NUM_BITREG] = {
/* ACPI_BITREG_RT_CLOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE,
ACPI_BITPOSITION_RT_CLOCK_ENABLE,
ACPI_BITMASK_RT_CLOCK_ENABLE},
- /* ACPI_BITREG_WAKE_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, 0, 0},
/* ACPI_BITREG_PCIEXP_WAKE_DISABLE */ {ACPI_REGISTER_PM1_ENABLE,
ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE,
ACPI_BITMASK_PCIEXP_WAKE_DISABLE},
@@ -575,6 +574,47 @@ char *acpi_ut_get_descriptor_name(void *object)
}
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_reference_name
+ *
+ * PARAMETERS: Object - An ACPI reference object
+ *
+ * RETURN: Pointer to a string
+ *
+ * DESCRIPTION: Decode a reference object sub-type to a string.
+ *
+ ******************************************************************************/
+
+/* Printable names of reference object sub-types */
+
+static const char *acpi_gbl_ref_class_names[] = {
+ /* 00 */ "Local",
+ /* 01 */ "Argument",
+ /* 02 */ "RefOf",
+ /* 03 */ "Index",
+ /* 04 */ "DdbHandle",
+ /* 05 */ "Named Object",
+ /* 06 */ "Debug"
+};
+
+const char *acpi_ut_get_reference_name(union acpi_operand_object *object)
+{
+ if (!object)
+ return "NULL Object";
+
+ if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND)
+ return "Not an Operand object";
+
+ if (object->common.type != ACPI_TYPE_LOCAL_REFERENCE)
+ return "Not a Reference object";
+
+ if (object->reference.class > ACPI_REFCLASS_MAX)
+ return "Unknown Reference class";
+
+ return acpi_gbl_ref_class_names[object->reference.class];
+}
+
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
/*
* Strings and procedures used for debug only
@@ -677,14 +717,14 @@ u8 acpi_ut_valid_object_type(acpi_object_type type)
*
* PARAMETERS: None
*
- * RETURN: None
+ * RETURN: Status
*
* DESCRIPTION: Init library globals. All globals that require specific
* initialization should be initialized here!
*
******************************************************************************/
-void acpi_ut_init_globals(void)
+acpi_status acpi_ut_init_globals(void)
{
acpi_status status;
u32 i;
@@ -695,7 +735,7 @@ void acpi_ut_init_globals(void)
status = acpi_ut_create_caches();
if (ACPI_FAILURE(status)) {
- return;
+ return_ACPI_STATUS(status);
}
/* Mutex locked flags */
@@ -772,8 +812,8 @@ void acpi_ut_init_globals(void)
acpi_gbl_display_final_mem_stats = FALSE;
#endif
- return_VOID;
+ return_ACPI_STATUS(AE_OK);
}
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
- ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
+ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index f34be677355..9089a158a87 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -995,6 +995,15 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
state->pkg.
this_target_obj, 0);
if (!state) {
+
+ /* Free any stacked Update State objects */
+
+ while (state_list) {
+ state =
+ acpi_ut_pop_generic_state
+ (&state_list);
+ acpi_ut_delete_generic_state(state);
+ }
return_ACPI_STATUS(AE_NO_MEMORY);
}
}
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index 916eff399eb..c354e7a42bc 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -43,7 +43,6 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
-#include <acpi/amlcode.h>
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utobject")
@@ -478,8 +477,8 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
case ACPI_TYPE_LOCAL_REFERENCE:
- switch (internal_object->reference.opcode) {
- case AML_INT_NAMEPATH_OP:
+ switch (internal_object->reference.class) {
+ case ACPI_REFCLASS_NAME:
/*
* Get the actual length of the full pathname to this object.
@@ -503,8 +502,10 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
* required eventually.
*/
ACPI_ERROR((AE_INFO,
- "Unsupported Reference opcode=%X in object %p",
- internal_object->reference.opcode,
+ "Cannot convert to external object - "
+ "unsupported Reference Class [%s] %X in object %p",
+ acpi_ut_get_reference_name(internal_object),
+ internal_object->reference.class,
internal_object));
status = AE_TYPE;
break;
@@ -513,7 +514,9 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
default:
- ACPI_ERROR((AE_INFO, "Unsupported type=%X in object %p",
+ ACPI_ERROR((AE_INFO, "Cannot convert to external object - "
+ "unsupported type [%s] %X in object %p",
+ acpi_ut_get_object_type_name(internal_object),
ACPI_GET_OBJECT_TYPE(internal_object),
internal_object));
status = AE_TYPE;
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index f8bdadf3c32..c198a4d4058 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -81,7 +81,12 @@ acpi_status __init acpi_initialize_subsystem(void)
/* Initialize all globals used by the subsystem */
- acpi_ut_init_globals();
+ status = acpi_ut_init_globals();
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During initialization of globals"));
+ return_ACPI_STATUS(status);
+ }
/* Create the default mutex objects */
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 10092614381..e827be36ee8 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -256,7 +256,7 @@ EXPORT_SYMBOL(acpi_extract_package);
acpi_status
acpi_evaluate_integer(acpi_handle handle,
acpi_string pathname,
- struct acpi_object_list *arguments, unsigned long *data)
+ struct acpi_object_list *arguments, unsigned long long *data)
{
acpi_status status = AE_OK;
union acpi_object *element;
@@ -288,7 +288,7 @@ acpi_evaluate_integer(acpi_handle handle,
*data = element->integer.value;
kfree(element);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%lu]\n", *data));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data));
return AE_OK;
}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index e8a51a1700f..a29b0ccac65 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -291,20 +291,20 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
int level);
static int acpi_video_device_lcd_get_level_current(
struct acpi_video_device *device,
- unsigned long *level);
+ unsigned long long *level);
static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static void acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
static int acpi_video_device_get_state(struct acpi_video_device *device,
- unsigned long *state);
+ unsigned long long *state);
static int acpi_video_output_get(struct output_device *od);
static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
/*backlight device sysfs support*/
static int acpi_video_get_brightness(struct backlight_device *bd)
{
- unsigned long cur_level;
+ unsigned long long cur_level;
int i;
struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd);
@@ -336,7 +336,7 @@ static struct backlight_ops acpi_backlight_ops = {
/*video output device sysfs support*/
static int acpi_video_output_get(struct output_device *od)
{
- unsigned long state;
+ unsigned long long state;
struct acpi_video_device *vd =
(struct acpi_video_device *)dev_get_drvdata(&od->dev);
acpi_video_device_get_state(vd, &state);
@@ -370,7 +370,7 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
- unsigned long level;
+ unsigned long long level;
int state;
acpi_video_device_lcd_get_level_current(video, &level);
@@ -410,7 +410,7 @@ static struct thermal_cooling_device_ops video_cooling_ops = {
/* device */
static int
-acpi_video_device_query(struct acpi_video_device *device, unsigned long *state)
+acpi_video_device_query(struct acpi_video_device *device, unsigned long long *state)
{
int status;
@@ -421,7 +421,7 @@ acpi_video_device_query(struct acpi_video_device *device, unsigned long *state)
static int
acpi_video_device_get_state(struct acpi_video_device *device,
- unsigned long *state)
+ unsigned long long *state)
{
int status;
@@ -436,7 +436,7 @@ acpi_video_device_set_state(struct acpi_video_device *device, int state)
int status;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
- unsigned long ret;
+ unsigned long long ret;
arg0.integer.value = state;
@@ -495,7 +495,7 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
static int
acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
- unsigned long *level)
+ unsigned long long *level)
{
if (device->cap._BQC)
return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL,
@@ -549,7 +549,7 @@ static int
acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
{
int status;
- unsigned long tmp;
+ unsigned long long tmp;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
@@ -564,7 +564,7 @@ acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
}
static int
-acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id)
+acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id)
{
int status;
@@ -575,7 +575,7 @@ acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id)
static int
acpi_video_bus_POST_options(struct acpi_video_bus *video,
- unsigned long *options)
+ unsigned long long *options)
{
int status;
@@ -918,7 +918,7 @@ static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
{
int status;
struct acpi_video_device *dev = seq->private;
- unsigned long state;
+ unsigned long long state;
if (!dev)
@@ -927,14 +927,14 @@ static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
status = acpi_video_device_get_state(dev, &state);
seq_printf(seq, "state: ");
if (ACPI_SUCCESS(status))
- seq_printf(seq, "0x%02lx\n", state);
+ seq_printf(seq, "0x%02llx\n", state);
else
seq_printf(seq, "<not supported>\n");
status = acpi_video_device_query(dev, &state);
seq_printf(seq, "query: ");
if (ACPI_SUCCESS(status))
- seq_printf(seq, "0x%02lx\n", state);
+ seq_printf(seq, "0x%02llx\n", state);
else
seq_printf(seq, "<not supported>\n");
@@ -1217,7 +1217,7 @@ static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_video_bus *video = seq->private;
- unsigned long options;
+ unsigned long long options;
int status;
@@ -1232,7 +1232,7 @@ static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
printk(KERN_WARNING PREFIX
"This indicates a BIOS bug. Please contact the manufacturer.\n");
}
- printk("%lx\n", options);
+ printk("%llx\n", options);
seq_printf(seq, "can POST: <integrated video>");
if (options & 2)
seq_printf(seq, " <PCI video>");
@@ -1256,7 +1256,7 @@ static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_video_bus *video = seq->private;
int status;
- unsigned long id;
+ unsigned long long id;
if (!video)
@@ -1303,7 +1303,7 @@ acpi_video_bus_write_POST(struct file *file,
struct seq_file *m = file->private_data;
struct acpi_video_bus *video = m->private;
char str[12] = { 0 };
- unsigned long opt, options;
+ unsigned long long opt, options;
if (!video || count + 1 > sizeof str)
@@ -1473,7 +1473,7 @@ static int
acpi_video_bus_get_one_device(struct acpi_device *device,
struct acpi_video_bus *video)
{
- unsigned long device_id;
+ unsigned long long device_id;
int status;
struct acpi_video_device *data;
struct acpi_video_device_attrib* attribute;
@@ -1491,7 +1491,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
- acpi_driver_data(device) = data;
+ device->driver_data = data;
data->device_id = device_id;
data->video = video;
@@ -1530,8 +1530,8 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
acpi_video_device_notify,
data);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing notify handler\n"));
+ printk(KERN_ERR PREFIX
+ "Error installing notify handler\n");
if(data->brightness)
kfree(data->brightness->levels);
kfree(data->brightness);
@@ -1724,7 +1724,7 @@ acpi_video_get_next_level(struct acpi_video_device *device,
static void
acpi_video_switch_brightness(struct acpi_video_device *device, int event)
{
- unsigned long level_current, level_next;
+ unsigned long long level_current, level_next;
if (!device->brightness)
return;
acpi_video_device_lcd_get_level_current(device, &level_current);
@@ -1745,8 +1745,8 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
status = acpi_video_bus_get_one_device(dev, video);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Cant attach device"));
+ printk(KERN_WARNING PREFIX
+ "Cant attach device");
continue;
}
}
@@ -1982,7 +1982,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
video->device = device;
strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
- acpi_driver_data(device) = video;
+ device->driver_data = video;
acpi_video_bus_find_cap(video);
error = acpi_video_bus_check(video);
@@ -2003,8 +2003,8 @@ static int acpi_video_bus_add(struct acpi_device *device)
ACPI_DEVICE_NOTIFY,
acpi_video_bus_notify, video);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing notify handler\n"));
+ printk(KERN_ERR PREFIX
+ "Error installing notify handler\n");
error = -ENODEV;
goto err_stop_video;
}
@@ -2058,7 +2058,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
acpi_video_bus_remove_fs(device);
err_free_video:
kfree(video);
- acpi_driver_data(device) = NULL;
+ device->driver_data = NULL;
return error;
}
diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c
index cfe2c833474..47cd7baf9b1 100644
--- a/drivers/acpi/wmi.c
+++ b/drivers/acpi/wmi.c
@@ -217,6 +217,35 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
return 0;
}
+static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
+{
+ struct guid_block *block = NULL;
+ char method[5];
+ struct acpi_object_list input;
+ union acpi_object params[1];
+ acpi_status status;
+ acpi_handle handle;
+
+ block = &wblock->gblock;
+ handle = wblock->handle;
+
+ if (!block)
+ return AE_NOT_EXIST;
+
+ input.count = 1;
+ input.pointer = params;
+ params[0].type = ACPI_TYPE_INTEGER;
+ params[0].integer.value = enable;
+
+ snprintf(method, 5, "WE%02X", block->notify_id);
+ status = acpi_evaluate_object(handle, method, &input, NULL);
+
+ if (status != AE_OK && status != AE_NOT_FOUND)
+ return status;
+ else
+ return AE_OK;
+}
+
/*
* Exported WMI functions
*/
@@ -242,7 +271,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
char method[4] = "WM";
if (!find_guid(guid_string, &wblock))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
block = &wblock->gblock;
handle = wblock->handle;
@@ -304,7 +333,7 @@ struct acpi_buffer *out)
return AE_BAD_PARAMETER;
if (!find_guid(guid_string, &wblock))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
block = &wblock->gblock;
handle = wblock->handle;
@@ -314,7 +343,7 @@ struct acpi_buffer *out)
/* Check GUID is a data block */
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
input.count = 1;
input.pointer = wq_params;
@@ -385,7 +414,7 @@ const struct acpi_buffer *in)
return AE_BAD_DATA;
if (!find_guid(guid_string, &wblock))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
block = &wblock->gblock;
handle = wblock->handle;
@@ -395,7 +424,7 @@ const struct acpi_buffer *in)
/* Check GUID is a data block */
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
input.count = 2;
input.pointer = params;
@@ -427,6 +456,7 @@ acpi_status wmi_install_notify_handler(const char *guid,
wmi_notify_handler handler, void *data)
{
struct wmi_block *block;
+ acpi_status status;
if (!guid || !handler)
return AE_BAD_PARAMETER;
@@ -441,7 +471,9 @@ wmi_notify_handler handler, void *data)
block->handler = handler;
block->handler_data = data;
- return AE_OK;
+ status = wmi_method_enable(block, 1);
+
+ return status;
}
EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
@@ -453,6 +485,7 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
acpi_status wmi_remove_notify_handler(const char *guid)
{
struct wmi_block *block;
+ acpi_status status;
if (!guid)
return AE_BAD_PARAMETER;
@@ -464,10 +497,12 @@ acpi_status wmi_remove_notify_handler(const char *guid)
if (!block->handler)
return AE_NULL_ENTRY;
+ status = wmi_method_enable(block, 0);
+
block->handler = NULL;
block->handler_data = NULL;
- return AE_OK;
+ return status;
}
EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 9330b7922f6..c012307d0ba 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
}
-static void ata_acpi_eject_device(acpi_handle handle)
-{
- struct acpi_object_list arg_list;
- union acpi_object arg;
-
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
-
- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
- &arg_list, NULL)))
- printk(KERN_ERR "Failed to evaluate _EJ0!\n");
-}
-
/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
{
@@ -157,7 +142,6 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
* @ap: ATA port ACPI event occurred
* @dev: ATA device ACPI event occurred (can be NULL)
* @event: ACPI event which occurred
- * @is_dock_event: boolean indicating whether the event was a dock one
*
* All ACPI bay / device realted events end up in this function. If
* the event is port-wide @dev is NULL. If the event is specific to a
@@ -171,117 +155,100 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
* ACPI notify handler context. May sleep.
*/
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
- u32 event, int is_dock_event)
+ u32 event)
{
- char event_string[12];
- char *envp[] = { event_string, NULL };
struct ata_eh_info *ehi = &ap->link.eh_info;
- struct kobject *kobj = NULL;
int wait = 0;
unsigned long flags;
- acpi_handle handle, tmphandle;
- unsigned long sta;
- acpi_status status;
+ acpi_handle handle;
- if (dev) {
- if (dev->sdev)
- kobj = &dev->sdev->sdev_gendev.kobj;
+ if (dev)
handle = dev->acpi_handle;
- } else {
- kobj = &ap->dev->kobj;
+ else
handle = ap->acpi_handle;
- }
-
- status = acpi_get_handle(handle, "_EJ0", &tmphandle);
- if (ACPI_FAILURE(status))
- /* This device does not support hotplug */
- return;
-
- if (event == ACPI_NOTIFY_BUS_CHECK ||
- event == ACPI_NOTIFY_DEVICE_CHECK)
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
spin_lock_irqsave(ap->lock, flags);
-
+ /*
+ * When dock driver calls into the routine, it will always use
+ * ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
+ * ACPI_NOTIFY_EJECT_REQUEST for remove
+ */
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
ata_ehi_push_desc(ehi, "ACPI event");
- if (ACPI_FAILURE(status)) {
- ata_port_printk(ap, KERN_ERR,
- "acpi: failed to determine bay status (0x%x)\n",
- status);
- break;
- }
-
- if (sta) {
- ata_ehi_hotplugged(ehi);
- ata_port_freeze(ap);
- } else {
- /* The device has gone - unplug it */
- ata_acpi_detach_device(ap, dev);
- wait = 1;
- }
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
break;
case ACPI_NOTIFY_EJECT_REQUEST:
ata_ehi_push_desc(ehi, "ACPI event");
- if (!is_dock_event)
- break;
-
- /* undock event - immediate unplug */
ata_acpi_detach_device(ap, dev);
wait = 1;
break;
}
- /* make sure kobj doesn't go away while ap->lock is released */
- kobject_get(kobj);
-
spin_unlock_irqrestore(ap->lock, flags);
- if (wait) {
+ if (wait)
ata_port_wait_eh(ap);
- ata_acpi_eject_device(handle);
- }
-
- if (kobj && !is_dock_event) {
- sprintf(event_string, "BAY_EVENT=%d", event);
- kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
- }
-
- kobject_put(kobj);
}
static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
{
struct ata_device *dev = data;
- ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1);
+ ata_acpi_handle_hotplug(dev->link->ap, dev, event);
}
static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
{
struct ata_port *ap = data;
- ata_acpi_handle_hotplug(ap, NULL, event, 1);
+ ata_acpi_handle_hotplug(ap, NULL, event);
}
-static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
+ u32 event)
{
- struct ata_device *dev = data;
+ struct kobject *kobj = NULL;
+ char event_string[20];
+ char *envp[] = { event_string, NULL };
+
+ if (dev) {
+ if (dev->sdev)
+ kobj = &dev->sdev->sdev_gendev.kobj;
+ } else
+ kobj = &ap->dev->kobj;
- ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0);
+ if (kobj) {
+ snprintf(event_string, 20, "BAY_EVENT=%d", event);
+ kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
+ }
}
-static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
{
- struct ata_port *ap = data;
+ ata_acpi_uevent(data, NULL, event);
+}
- ata_acpi_handle_hotplug(ap, NULL, event, 0);
+static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_device *dev = data;
+ ata_acpi_uevent(dev->link->ap, dev, event);
}
+static struct acpi_dock_ops ata_acpi_dev_dock_ops = {
+ .handler = ata_acpi_dev_notify_dock,
+ .uevent = ata_acpi_dev_uevent,
+};
+
+static struct acpi_dock_ops ata_acpi_ap_dock_ops = {
+ .handler = ata_acpi_ap_notify_dock,
+ .uevent = ata_acpi_ap_uevent,
+};
+
/**
* ata_acpi_associate - associate ATA host with ACPI objects
* @host: target ATA host
@@ -315,24 +282,18 @@ void ata_acpi_associate(struct ata_host *host)
ata_acpi_associate_ide_port(ap);
if (ap->acpi_handle) {
- acpi_install_notify_handler(ap->acpi_handle,
- ACPI_SYSTEM_NOTIFY,
- ata_acpi_ap_notify, ap);
/* we might be on a docking station */
register_hotplug_dock_device(ap->acpi_handle,
- ata_acpi_ap_notify_dock, ap);
+ &ata_acpi_ap_dock_ops, ap);
}
for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
struct ata_device *dev = &ap->link.device[j];
if (dev->acpi_handle) {
- acpi_install_notify_handler(dev->acpi_handle,
- ACPI_SYSTEM_NOTIFY,
- ata_acpi_dev_notify, dev);
/* we might be on a docking station */
register_hotplug_dock_device(dev->acpi_handle,
- ata_acpi_dev_notify_dock, dev);
+ &ata_acpi_dev_dock_ops, dev);
}
}
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 1ee9499bd34..bbb3cae5749 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5373,6 +5373,8 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
#ifdef CONFIG_ATA_SFF
INIT_DELAYED_WORK(&ap->port_task, ata_pio_task);
+#else
+ INIT_DELAYED_WORK(&ap->port_task, NULL);
#endif
INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index a93247cc395..5d687d7cffa 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1206,7 +1206,10 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
ata_eh_clear_action(link, dev, ehi, action);
- if (!(ehc->i.flags & ATA_EHI_QUIET))
+ /* About to take EH action, set RECOVERED. Ignore actions on
+ * slave links as master will do them again.
+ */
+ if (!(ehc->i.flags & ATA_EHI_QUIET) && link != ap->slave_link)
ap->pflags |= ATA_PFLAG_RECOVERED;
spin_unlock_irqrestore(ap->lock, flags);
@@ -2010,8 +2013,13 @@ void ata_eh_autopsy(struct ata_port *ap)
struct ata_eh_context *mehc = &ap->link.eh_context;
struct ata_eh_context *sehc = &ap->slave_link->eh_context;
+ /* transfer control flags from master to slave */
+ sehc->i.flags |= mehc->i.flags & ATA_EHI_TO_SLAVE_MASK;
+
+ /* perform autopsy on the slave link */
ata_eh_link_autopsy(ap->slave_link);
+ /* transfer actions from slave to master and clear slave */
ata_eh_about_to_do(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS);
mehc->i.action |= sehc->i.action;
mehc->i.dev_action[1] |= sehc->i.dev_action[1];
@@ -2447,14 +2455,14 @@ int ata_eh_reset(struct ata_link *link, int classify,
dev->pio_mode = XFER_PIO_0;
dev->flags &= ~ATA_DFLAG_SLEEPING;
- if (ata_phys_link_offline(ata_dev_phys_link(dev)))
- continue;
-
- /* apply class override */
- if (lflags & ATA_LFLAG_ASSUME_ATA)
- classes[dev->devno] = ATA_DEV_ATA;
- else if (lflags & ATA_LFLAG_ASSUME_SEMB)
- classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
+ if (!ata_phys_link_offline(ata_dev_phys_link(dev))) {
+ /* apply class override */
+ if (lflags & ATA_LFLAG_ASSUME_ATA)
+ classes[dev->devno] = ATA_DEV_ATA;
+ else if (lflags & ATA_LFLAG_ASSUME_SEMB)
+ classes[dev->devno] = ATA_DEV_SEMB_UNSUP;
+ } else
+ classes[dev->devno] = ATA_DEV_NONE;
}
/* record current link speed */
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 2a4c516894f..4b473948632 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -2153,8 +2153,17 @@ void ata_sff_error_handler(struct ata_port *ap)
*/
void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc)
{
- if (qc->ap->ioaddr.bmdma_addr)
+ struct ata_port *ap = qc->ap;
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ if (ap->ioaddr.bmdma_addr)
ata_bmdma_stop(qc);
+
+ spin_unlock_irqrestore(ap->lock, flags);
}
/**
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 1cfa74535d9..5b72e734300 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -70,6 +70,7 @@ enum {
static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
+static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
static void svia_noop_freeze(struct ata_port *ap);
static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -103,21 +104,26 @@ static struct scsi_host_template svia_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
-static struct ata_port_operations vt6420_sata_ops = {
+static struct ata_port_operations svia_base_ops = {
.inherits = &ata_bmdma_port_ops,
+ .sff_tf_load = svia_tf_load,
+};
+
+static struct ata_port_operations vt6420_sata_ops = {
+ .inherits = &svia_base_ops,
.freeze = svia_noop_freeze,
.prereset = vt6420_prereset,
};
static struct ata_port_operations vt6421_pata_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &svia_base_ops,
.cable_detect = vt6421_pata_cable_detect,
.set_piomode = vt6421_set_pio_mode,
.set_dmamode = vt6421_set_dma_mode,
};
static struct ata_port_operations vt6421_sata_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &svia_base_ops,
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
};
@@ -168,6 +174,29 @@ static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
return 0;
}
+/**
+ * svia_tf_load - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Outputs ATA taskfile to standard ATA host controller.
+ *
+ * This is to fix the internal bug of via chipsets, which will
+ * reset the device register after changing the IEN bit on ctl
+ * register.
+ */
+static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ struct ata_taskfile ttf;
+
+ if (tf->ctl != ap->last_ctl) {
+ ttf = *tf;
+ ttf.flags |= ATA_TFLAG_DEVICE;
+ tf = &ttf;
+ }
+ ata_sff_tf_load(ap, tf);
+}
+
static void svia_noop_freeze(struct ata_port *ap)
{
/* Some VIA controllers choke if ATA_NIEN is manipulated in
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index af0d175c025..5260e9e0df4 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -21,6 +21,8 @@
#include <linux/memory_hotplug.h>
#include <linux/mm.h>
#include <linux/mutex.h>
+#include <linux/stat.h>
+
#include <asm/atomic.h>
#include <asm/uaccess.h>
@@ -325,7 +327,7 @@ memory_probe_store(struct class *class, const char *buf, size_t count)
return count;
}
-static CLASS_ATTR(probe, 0700, NULL, memory_probe_store);
+static CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
static int memory_probe_init(void)
{
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 5116b78c632..f5207090885 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -13,6 +13,7 @@
#include <linux/nodemask.h>
#include <linux/cpu.h>
#include <linux/device.h>
+#include <linux/swap.h>
static struct sysdev_class node_class = {
.name = "node",
@@ -61,34 +62,52 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
si_meminfo_node(&i, nid);
n = sprintf(buf, "\n"
- "Node %d MemTotal: %8lu kB\n"
- "Node %d MemFree: %8lu kB\n"
- "Node %d MemUsed: %8lu kB\n"
- "Node %d Active: %8lu kB\n"
- "Node %d Inactive: %8lu kB\n"
+ "Node %d MemTotal: %8lu kB\n"
+ "Node %d MemFree: %8lu kB\n"
+ "Node %d MemUsed: %8lu kB\n"
+ "Node %d Active: %8lu kB\n"
+ "Node %d Inactive: %8lu kB\n"
+ "Node %d Active(anon): %8lu kB\n"
+ "Node %d Inactive(anon): %8lu kB\n"
+ "Node %d Active(file): %8lu kB\n"
+ "Node %d Inactive(file): %8lu kB\n"
+#ifdef CONFIG_UNEVICTABLE_LRU
+ "Node %d Unevictable: %8lu kB\n"
+ "Node %d Mlocked: %8lu kB\n"
+#endif
#ifdef CONFIG_HIGHMEM
- "Node %d HighTotal: %8lu kB\n"
- "Node %d HighFree: %8lu kB\n"
- "Node %d LowTotal: %8lu kB\n"
- "Node %d LowFree: %8lu kB\n"
+ "Node %d HighTotal: %8lu kB\n"
+ "Node %d HighFree: %8lu kB\n"
+ "Node %d LowTotal: %8lu kB\n"
+ "Node %d LowFree: %8lu kB\n"
#endif
- "Node %d Dirty: %8lu kB\n"
- "Node %d Writeback: %8lu kB\n"
- "Node %d FilePages: %8lu kB\n"
- "Node %d Mapped: %8lu kB\n"
- "Node %d AnonPages: %8lu kB\n"
- "Node %d PageTables: %8lu kB\n"
- "Node %d NFS_Unstable: %8lu kB\n"
- "Node %d Bounce: %8lu kB\n"
- "Node %d WritebackTmp: %8lu kB\n"
- "Node %d Slab: %8lu kB\n"
- "Node %d SReclaimable: %8lu kB\n"
- "Node %d SUnreclaim: %8lu kB\n",
+ "Node %d Dirty: %8lu kB\n"
+ "Node %d Writeback: %8lu kB\n"
+ "Node %d FilePages: %8lu kB\n"
+ "Node %d Mapped: %8lu kB\n"
+ "Node %d AnonPages: %8lu kB\n"
+ "Node %d PageTables: %8lu kB\n"
+ "Node %d NFS_Unstable: %8lu kB\n"
+ "Node %d Bounce: %8lu kB\n"
+ "Node %d WritebackTmp: %8lu kB\n"
+ "Node %d Slab: %8lu kB\n"
+ "Node %d SReclaimable: %8lu kB\n"
+ "Node %d SUnreclaim: %8lu kB\n",
nid, K(i.totalram),
nid, K(i.freeram),
nid, K(i.totalram - i.freeram),
- nid, K(node_page_state(nid, NR_ACTIVE)),
- nid, K(node_page_state(nid, NR_INACTIVE)),
+ nid, K(node_page_state(nid, NR_ACTIVE_ANON) +
+ node_page_state(nid, NR_ACTIVE_FILE)),
+ nid, K(node_page_state(nid, NR_INACTIVE_ANON) +
+ node_page_state(nid, NR_INACTIVE_FILE)),
+ nid, K(node_page_state(nid, NR_ACTIVE_ANON)),
+ nid, K(node_page_state(nid, NR_INACTIVE_ANON)),
+ nid, K(node_page_state(nid, NR_ACTIVE_FILE)),
+ nid, K(node_page_state(nid, NR_INACTIVE_FILE)),
+#ifdef CONFIG_UNEVICTABLE_LRU
+ nid, K(node_page_state(nid, NR_UNEVICTABLE)),
+ nid, K(node_page_state(nid, NR_MLOCK)),
+#endif
#ifdef CONFIG_HIGHMEM
nid, K(i.totalhigh),
nid, K(i.freehigh),
@@ -173,6 +192,8 @@ int register_node(struct node *node, int num, struct node *parent)
sysdev_create_file(&node->sysdev, &attr_meminfo);
sysdev_create_file(&node->sysdev, &attr_numastat);
sysdev_create_file(&node->sysdev, &attr_distance);
+
+ scan_unevictable_register_node(node);
}
return error;
}
@@ -192,6 +213,8 @@ void unregister_node(struct node *node)
sysdev_remove_file(&node->sysdev, &attr_numastat);
sysdev_remove_file(&node->sysdev, &attr_distance);
+ scan_unevictable_unregister_node(node);
+
sysdev_unregister(&node->sysdev);
}
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index a002a381df9..f6a337c34ac 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -72,9 +72,9 @@ static long disk_size(DAC960_Controller_T *p, int drive_nr)
}
}
-static int DAC960_open(struct inode *inode, struct file *file)
+static int DAC960_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct gendisk *disk = bdev->bd_disk;
DAC960_Controller_T *p = disk->queue->queuedata;
int drive_nr = (long)disk->private_data;
@@ -89,7 +89,7 @@ static int DAC960_open(struct inode *inode, struct file *file)
return -ENXIO;
}
- check_disk_change(inode->i_bdev);
+ check_disk_change(bdev);
if (!get_capacity(p->disks[drive_nr]))
return -ENXIO;
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 7516baff3bb..4b1d4ac960f 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1437,10 +1437,11 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
-static int fd_ioctl(struct inode *inode, struct file *filp,
+static int fd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long param)
{
- int drive = iminor(inode) & 3;
+ struct amiga_floppy_struct *p = bdev->bd_disk->private_data;
+ int drive = p - unit;
static struct floppy_struct getprm;
void __user *argp = (void __user *)param;
@@ -1451,7 +1452,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
rel_fdc();
return -EBUSY;
}
- fsync_bdev(inode->i_bdev);
+ fsync_bdev(bdev);
if (fd_motor_on(drive) == 0) {
rel_fdc();
return -ENODEV;
@@ -1464,12 +1465,12 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
rel_fdc();
break;
case FDFMTTRK:
- if (param < unit[drive].type->tracks * unit[drive].type->heads)
+ if (param < p->type->tracks * p->type->heads)
{
get_fdc(drive);
if (fd_seek(drive,param) != 0){
- memset(unit[drive].trackbuf, FD_FILL_BYTE,
- unit[drive].dtype->sects * unit[drive].type->sect_mult * 512);
+ memset(p->trackbuf, FD_FILL_BYTE,
+ p->dtype->sects * p->type->sect_mult * 512);
non_int_flush_track(drive);
}
floppy_off(drive);
@@ -1480,14 +1481,14 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
break;
case FDFMTEND:
floppy_off(drive);
- invalidate_bdev(inode->i_bdev);
+ invalidate_bdev(bdev);
break;
case FDGETPRM:
memset((void *)&getprm, 0, sizeof (getprm));
- getprm.track=unit[drive].type->tracks;
- getprm.head=unit[drive].type->heads;
- getprm.sect=unit[drive].dtype->sects * unit[drive].type->sect_mult;
- getprm.size=unit[drive].blocks;
+ getprm.track=p->type->tracks;
+ getprm.head=p->type->heads;
+ getprm.sect=p->dtype->sects * p->type->sect_mult;
+ getprm.size=p->blocks;
if (copy_to_user(argp, &getprm, sizeof(struct floppy_struct)))
return -EFAULT;
break;
@@ -1500,10 +1501,10 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
break;
#ifdef RAW_IOCTL
case IOCTL_RAW_TRACK:
- if (copy_to_user(argp, raw_buf, unit[drive].type->read_size))
+ if (copy_to_user(argp, raw_buf, p->type->read_size))
return -EFAULT;
else
- return unit[drive].type->read_size;
+ return p->type->read_size;
#endif
default:
printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.",
@@ -1548,10 +1549,10 @@ static void fd_probe(int dev)
* /dev/PS0 etc), and disallows simultaneous access to the same
* drive with different device numbers.
*/
-static int floppy_open(struct inode *inode, struct file *filp)
+static int floppy_open(struct block_device *bdev, fmode_t mode)
{
- int drive = iminor(inode) & 3;
- int system = (iminor(inode) & 4) >> 2;
+ int drive = MINOR(bdev->bd_dev) & 3;
+ int system = (MINOR(bdev->bd_dev) & 4) >> 2;
int old_dev;
unsigned long flags;
@@ -1560,9 +1561,9 @@ static int floppy_open(struct inode *inode, struct file *filp)
if (fd_ref[drive] && old_dev != system)
return -EBUSY;
- if (filp && filp->f_mode & 3) {
- check_disk_change(inode->i_bdev);
- if (filp->f_mode & 2 ) {
+ if (mode & (FMODE_READ|FMODE_WRITE)) {
+ check_disk_change(bdev);
+ if (mode & FMODE_WRITE) {
int wrprot;
get_fdc(drive);
@@ -1592,9 +1593,10 @@ static int floppy_open(struct inode *inode, struct file *filp)
return 0;
}
-static int floppy_release(struct inode * inode, struct file * filp)
+static int floppy_release(struct gendisk *disk, fmode_t mode)
{
- int drive = iminor(inode) & 3;
+ struct amiga_floppy_struct *p = disk->private_data;
+ int drive = p - unit;
if (unit[drive].dirty == 1) {
del_timer (flush_track_timer + drive);
@@ -1650,7 +1652,7 @@ static struct block_device_operations floppy_fops = {
.owner = THIS_MODULE,
.open = floppy_open,
.release = floppy_release,
- .ioctl = fd_ioctl,
+ .locked_ioctl = fd_ioctl,
.getgeo = fd_getgeo,
.media_changed = amiga_floppy_change,
};
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index b82654e883a..1747dd272cd 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -90,7 +90,7 @@ static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
static struct device_attribute dev_attr_firmware_version = {
- .attr = { .name = "firmware-version", .mode = S_IRUGO, .owner = THIS_MODULE },
+ .attr = { .name = "firmware-version", .mode = S_IRUGO },
.show = aoedisk_show_fwver,
};
@@ -118,13 +118,11 @@ aoedisk_rm_sysfs(struct aoedev *d)
}
static int
-aoeblk_open(struct inode *inode, struct file *filp)
+aoeblk_open(struct block_device *bdev, fmode_t mode)
{
- struct aoedev *d;
+ struct aoedev *d = bdev->bd_disk->private_data;
ulong flags;
- d = inode->i_bdev->bd_disk->private_data;
-
spin_lock_irqsave(&d->lock, flags);
if (d->flags & DEVFL_UP) {
d->nopen++;
@@ -136,13 +134,11 @@ aoeblk_open(struct inode *inode, struct file *filp)
}
static int
-aoeblk_release(struct inode *inode, struct file *filp)
+aoeblk_release(struct gendisk *disk, fmode_t mode)
{
- struct aoedev *d;
+ struct aoedev *d = disk->private_data;
ulong flags;
- d = inode->i_bdev->bd_disk->private_data;
-
spin_lock_irqsave(&d->lock, flags);
if (--d->nopen == 0) {
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 432cf401829..69e1df7dfa1 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -361,13 +361,13 @@ static void finish_fdc( void );
static void finish_fdc_done( int dummy );
static void setup_req_params( int drive );
static void redo_fd_request( void);
-static int fd_ioctl( struct inode *inode, struct file *filp, unsigned int
+static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
cmd, unsigned long param);
static void fd_probe( int drive );
static int fd_test_drive_present( int drive );
static void config_types( void );
-static int floppy_open( struct inode *inode, struct file *filp );
-static int floppy_release( struct inode * inode, struct file * filp );
+static int floppy_open(struct block_device *bdev, fmode_t mode);
+static int floppy_release(struct gendisk *disk, fmode_t mode);
/************************* End of Prototypes **************************/
@@ -1483,10 +1483,10 @@ void do_fd_request(struct request_queue * q)
atari_enable_irq( IRQ_MFP_FDC );
}
-static int fd_ioctl(struct inode *inode, struct file *filp,
+static int fd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long param)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct gendisk *disk = bdev->bd_disk;
struct atari_floppy_struct *floppy = disk->private_data;
int drive = floppy - unit;
int type = floppy->type;
@@ -1661,7 +1661,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
/* invalidate the buffer track to force a reread */
BufferDrive = -1;
set_bit(drive, &fake_change);
- check_disk_change(inode->i_bdev);
+ check_disk_change(bdev);
return 0;
default:
return -EINVAL;
@@ -1804,37 +1804,36 @@ static void __init config_types( void )
* drive with different device numbers.
*/
-static int floppy_open( struct inode *inode, struct file *filp )
+static int floppy_open(struct block_device *bdev, fmode_t mode)
{
- struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data;
- int type = iminor(inode) >> 2;
+ struct atari_floppy_struct *p = bdev->bd_disk->private_data;
+ int type = MINOR(bdev->bd_dev) >> 2;
DPRINT(("fd_open: type=%d\n",type));
if (p->ref && p->type != type)
return -EBUSY;
- if (p->ref == -1 || (p->ref && filp->f_flags & O_EXCL))
+ if (p->ref == -1 || (p->ref && mode & FMODE_EXCL))
return -EBUSY;
- if (filp->f_flags & O_EXCL)
+ if (mode & FMODE_EXCL)
p->ref = -1;
else
p->ref++;
p->type = type;
- if (filp->f_flags & O_NDELAY)
+ if (mode & FMODE_NDELAY)
return 0;
- if (filp->f_mode & 3) {
- check_disk_change(inode->i_bdev);
- if (filp->f_mode & 2) {
+ if (mode & (FMODE_READ|FMODE_WRITE)) {
+ check_disk_change(bdev);
+ if (mode & FMODE_WRITE) {
if (p->wpstat) {
if (p->ref < 0)
p->ref = 0;
else
p->ref--;
- floppy_release(inode, filp);
return -EROFS;
}
}
@@ -1843,9 +1842,9 @@ static int floppy_open( struct inode *inode, struct file *filp )
}
-static int floppy_release( struct inode * inode, struct file * filp )
+static int floppy_release(struct gendisk *disk, fmode_t mode)
{
- struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data;
+ struct atari_floppy_struct *p = disk->private_data;
if (p->ref < 0)
p->ref = 0;
else if (!p->ref--) {
@@ -1859,7 +1858,7 @@ static struct block_device_operations floppy_fops = {
.owner = THIS_MODULE,
.open = floppy_open,
.release = floppy_release,
- .ioctl = fd_ioctl,
+ .locked_ioctl = fd_ioctl,
.media_changed = check_floppy_change,
.revalidate_disk= floppy_revalidate,
};
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index d070d492e38..bdd4f5f4557 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -340,11 +340,10 @@ static int brd_direct_access (struct block_device *bdev, sector_t sector,
}
#endif
-static int brd_ioctl(struct inode *inode, struct file *file,
+static int brd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
int error;
- struct block_device *bdev = inode->i_bdev;
struct brd_device *brd = bdev->bd_disk->private_data;
if (cmd != BLKFLSBUF)
@@ -376,7 +375,7 @@ static int brd_ioctl(struct inode *inode, struct file *file,
static struct block_device_operations brd_fops = {
.owner = THIS_MODULE,
- .ioctl = brd_ioctl,
+ .locked_ioctl = brd_ioctl,
#ifdef CONFIG_BLK_DEV_XIP
.direct_access = brd_direct_access,
#endif
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 1e1f9153000..4023885353e 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -152,9 +152,9 @@ static ctlr_info_t *hba[MAX_CTLR];
static void do_cciss_request(struct request_queue *q);
static irqreturn_t do_cciss_intr(int irq, void *dev_id);
-static int cciss_open(struct inode *inode, struct file *filep);
-static int cciss_release(struct inode *inode, struct file *filep);
-static int cciss_ioctl(struct inode *inode, struct file *filep,
+static int cciss_open(struct block_device *bdev, fmode_t mode);
+static int cciss_release(struct gendisk *disk, fmode_t mode);
+static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg);
static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
@@ -192,14 +192,15 @@ static void cciss_procinit(int i)
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_COMPAT
-static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
+static int cciss_compat_ioctl(struct block_device *, fmode_t,
+ unsigned, unsigned long);
#endif
static struct block_device_operations cciss_fops = {
.owner = THIS_MODULE,
.open = cciss_open,
.release = cciss_release,
- .ioctl = cciss_ioctl,
+ .locked_ioctl = cciss_ioctl,
.getgeo = cciss_getgeo,
#ifdef CONFIG_COMPAT
.compat_ioctl = cciss_compat_ioctl,
@@ -547,13 +548,13 @@ static inline drive_info_struct *get_drv(struct gendisk *disk)
/*
* Open. Make sure the device is really there.
*/
-static int cciss_open(struct inode *inode, struct file *filep)
+static int cciss_open(struct block_device *bdev, fmode_t mode)
{
- ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
- drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk);
+ ctlr_info_t *host = get_host(bdev->bd_disk);
+ drive_info_struct *drv = get_drv(bdev->bd_disk);
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name);
+ printk(KERN_DEBUG "cciss_open %s\n", bdev->bd_disk->disk_name);
#endif /* CCISS_DEBUG */
if (host->busy_initializing || drv->busy_configuring)
@@ -567,9 +568,9 @@ static int cciss_open(struct inode *inode, struct file *filep)
* for "raw controller".
*/
if (drv->heads == 0) {
- if (iminor(inode) != 0) { /* not node 0? */
+ if (MINOR(bdev->bd_dev) != 0) { /* not node 0? */
/* if not node 0 make sure it is a partition = 0 */
- if (iminor(inode) & 0x0f) {
+ if (MINOR(bdev->bd_dev) & 0x0f) {
return -ENXIO;
/* if it is, make sure we have a LUN ID */
} else if (drv->LunID == 0) {
@@ -587,14 +588,13 @@ static int cciss_open(struct inode *inode, struct file *filep)
/*
* Close. Sync first.
*/
-static int cciss_release(struct inode *inode, struct file *filep)
+static int cciss_release(struct gendisk *disk, fmode_t mode)
{
- ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
- drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk);
+ ctlr_info_t *host = get_host(disk);
+ drive_info_struct *drv = get_drv(disk);
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "cciss_release %s\n",
- inode->i_bdev->bd_disk->disk_name);
+ printk(KERN_DEBUG "cciss_release %s\n", disk->disk_name);
#endif /* CCISS_DEBUG */
drv->usage_count--;
@@ -604,21 +604,23 @@ static int cciss_release(struct inode *inode, struct file *filep)
#ifdef CONFIG_COMPAT
-static int do_ioctl(struct file *f, unsigned cmd, unsigned long arg)
+static int do_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg)
{
int ret;
lock_kernel();
- ret = cciss_ioctl(f->f_path.dentry->d_inode, f, cmd, arg);
+ ret = cciss_ioctl(bdev, mode, cmd, arg);
unlock_kernel();
return ret;
}
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
- unsigned long arg);
-static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd,
- unsigned long arg);
+static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg);
+static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg);
-static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
+static int cciss_compat_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg)
{
switch (cmd) {
case CCISS_GETPCIINFO:
@@ -636,20 +638,20 @@ static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
case CCISS_REGNEWD:
case CCISS_RESCANDISK:
case CCISS_GETLUNINFO:
- return do_ioctl(f, cmd, arg);
+ return do_ioctl(bdev, mode, cmd, arg);
case CCISS_PASSTHRU32:
- return cciss_ioctl32_passthru(f, cmd, arg);
+ return cciss_ioctl32_passthru(bdev, mode, cmd, arg);
case CCISS_BIG_PASSTHRU32:
- return cciss_ioctl32_big_passthru(f, cmd, arg);
+ return cciss_ioctl32_big_passthru(bdev, mode, cmd, arg);
default:
return -ENOIOCTLCMD;
}
}
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
- unsigned long arg)
+static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg)
{
IOCTL32_Command_struct __user *arg32 =
(IOCTL32_Command_struct __user *) arg;
@@ -676,7 +678,7 @@ static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
if (err)
return -EFAULT;
- err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long)p);
+ err = do_ioctl(bdev, mode, CCISS_PASSTHRU, (unsigned long)p);
if (err)
return err;
err |=
@@ -687,8 +689,8 @@ static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
return err;
}
-static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd,
- unsigned long arg)
+static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg)
{
BIG_IOCTL32_Command_struct __user *arg32 =
(BIG_IOCTL32_Command_struct __user *) arg;
@@ -717,7 +719,7 @@ static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd,
if (err)
return -EFAULT;
- err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long)p);
+ err = do_ioctl(bdev, mode, CCISS_BIG_PASSTHRU, (unsigned long)p);
if (err)
return err;
err |=
@@ -745,10 +747,9 @@ static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo)
/*
* ioctl
*/
-static int cciss_ioctl(struct inode *inode, struct file *filep,
+static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
ctlr_info_t *host = get_host(disk);
drive_info_struct *drv = get_drv(disk);
@@ -1232,7 +1233,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
case SG_EMULATED_HOST:
case SG_IO:
case SCSI_IOCTL_SEND_COMMAND:
- return scsi_cmd_ioctl(filep, disk->queue, disk, cmd, argp);
+ return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
/* scsi_cmd_ioctl would normally handle these, below, but */
/* they aren't a good fit for cciss, as CD-ROMs are */
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 3d967525e9a..47d233c6d0b 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -156,9 +156,9 @@ static int sendcmd(
unsigned int blkcnt,
unsigned int log_unit );
-static int ida_open(struct inode *inode, struct file *filep);
-static int ida_release(struct inode *inode, struct file *filep);
-static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
+static int ida_open(struct block_device *bdev, fmode_t mode);
+static int ida_release(struct gendisk *disk, fmode_t mode);
+static int ida_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg);
static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo);
static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io);
@@ -197,7 +197,7 @@ static struct block_device_operations ida_fops = {
.owner = THIS_MODULE,
.open = ida_open,
.release = ida_release,
- .ioctl = ida_ioctl,
+ .locked_ioctl = ida_ioctl,
.getgeo = ida_getgeo,
.revalidate_disk= ida_revalidate,
};
@@ -818,12 +818,12 @@ DBGINFO(
/*
* Open. Make sure the device is really there.
*/
-static int ida_open(struct inode *inode, struct file *filep)
+static int ida_open(struct block_device *bdev, fmode_t mode)
{
- drv_info_t *drv = get_drv(inode->i_bdev->bd_disk);
- ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
+ drv_info_t *drv = get_drv(bdev->bd_disk);
+ ctlr_info_t *host = get_host(bdev->bd_disk);
- DBGINFO(printk("ida_open %s\n", inode->i_bdev->bd_disk->disk_name));
+ DBGINFO(printk("ida_open %s\n", bdev->bd_disk->disk_name));
/*
* Root is allowed to open raw volume zero even if it's not configured
* so array config can still work. I don't think I really like this,
@@ -843,9 +843,9 @@ static int ida_open(struct inode *inode, struct file *filep)
/*
* Close. Sync first.
*/
-static int ida_release(struct inode *inode, struct file *filep)
+static int ida_release(struct gendisk *disk, fmode_t mode)
{
- ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
+ ctlr_info_t *host = get_host(disk);
host->usage_count--;
return 0;
}
@@ -1128,10 +1128,10 @@ static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo)
* ida_ioctl does some miscellaneous stuff like reporting drive geometry,
* setting readahead and submitting commands from userspace to the controller.
*/
-static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
+static int ida_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
{
- drv_info_t *drv = get_drv(inode->i_bdev->bd_disk);
- ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
+ drv_info_t *drv = get_drv(bdev->bd_disk);
+ ctlr_info_t *host = get_host(bdev->bd_disk);
int error;
ida_ioctl_t __user *io = (ida_ioctl_t __user *)arg;
ida_ioctl_t *my_io;
@@ -1165,7 +1165,7 @@ out_passthru:
put_user(host->ctlr_sig, (int __user *)arg);
return 0;
case IDAREVALIDATEVOLS:
- if (iminor(inode) != 0)
+ if (MINOR(bdev->bd_dev) != 0)
return -ENXIO;
return revalidate_allvol(host);
case IDADRIVERVERSION:
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 2cea27aba9a..14db747a636 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3450,14 +3450,14 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
-static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
unsigned long param)
{
-#define FD_IOCTL_ALLOWED ((filp) && (filp)->private_data)
+#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
#define OUT(c,x) case c: outparam = (const char *) (x); break
#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
- int drive = (long)inode->i_bdev->bd_disk->private_data;
+ int drive = (long)bdev->bd_disk->private_data;
int type = ITYPE(UDRS->fd_device);
int i;
int ret;
@@ -3516,11 +3516,11 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
current_type[drive] = NULL;
floppy_sizes[drive] = MAX_DISK_SIZE << 1;
UDRS->keep_data = 0;
- return invalidate_drive(inode->i_bdev);
+ return invalidate_drive(bdev);
case FDSETPRM:
case FDDEFPRM:
return set_geometry(cmd, &inparam.g,
- drive, type, inode->i_bdev);
+ drive, type, bdev);
case FDGETPRM:
ECALL(get_floppy_geometry(drive, type,
(struct floppy_struct **)
@@ -3551,7 +3551,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
case FDFMTEND:
case FDFLUSH:
LOCK_FDC(drive, 1);
- return invalidate_drive(inode->i_bdev);
+ return invalidate_drive(bdev);
case FDSETEMSGTRESH:
UDP->max_errors.reporting =
@@ -3659,9 +3659,9 @@ static void __init config_types(void)
printk("\n");
}
-static int floppy_release(struct inode *inode, struct file *filp)
+static int floppy_release(struct gendisk *disk, fmode_t mode)
{
- int drive = (long)inode->i_bdev->bd_disk->private_data;
+ int drive = (long)disk->private_data;
mutex_lock(&open_lock);
if (UDRS->fd_ref < 0)
@@ -3682,18 +3682,17 @@ static int floppy_release(struct inode *inode, struct file *filp)
* /dev/PS0 etc), and disallows simultaneous access to the same
* drive with different device numbers.
*/
-static int floppy_open(struct inode *inode, struct file *filp)
+static int floppy_open(struct block_device *bdev, fmode_t mode)
{
- int drive = (long)inode->i_bdev->bd_disk->private_data;
- int old_dev;
+ int drive = (long)bdev->bd_disk->private_data;
+ int old_dev, new_dev;
int try;
int res = -EBUSY;
char *tmp;
- filp->private_data = (void *)0;
mutex_lock(&open_lock);
old_dev = UDRS->fd_device;
- if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev)
+ if (opened_bdev[drive] && opened_bdev[drive] != bdev)
goto out2;
if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
@@ -3701,15 +3700,15 @@ static int floppy_open(struct inode *inode, struct file *filp)
USETF(FD_VERIFY);
}
- if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
+ if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
goto out2;
- if (filp->f_flags & O_EXCL)
+ if (mode & FMODE_EXCL)
UDRS->fd_ref = -1;
else
UDRS->fd_ref++;
- opened_bdev[drive] = inode->i_bdev;
+ opened_bdev[drive] = bdev;
res = -ENXIO;
@@ -3744,31 +3743,26 @@ static int floppy_open(struct inode *inode, struct file *filp)
}
}
- UDRS->fd_device = iminor(inode);
- set_capacity(disks[drive], floppy_sizes[iminor(inode)]);
- if (old_dev != -1 && old_dev != iminor(inode)) {
+ new_dev = MINOR(bdev->bd_dev);
+ UDRS->fd_device = new_dev;
+ set_capacity(disks[drive], floppy_sizes[new_dev]);
+ if (old_dev != -1 && old_dev != new_dev) {
if (buffer_drive == drive)
buffer_track = -1;
}
- /* Allow ioctls if we have write-permissions even if read-only open.
- * Needed so that programs such as fdrawcmd still can work on write
- * protected disks */
- if ((filp->f_mode & FMODE_WRITE) || !file_permission(filp, MAY_WRITE))
- filp->private_data = (void *)8;
-
if (UFDCS->rawcmd == 1)
UFDCS->rawcmd = 2;
- if (!(filp->f_flags & O_NDELAY)) {
- if (filp->f_mode & 3) {
+ if (!(mode & FMODE_NDELAY)) {
+ if (mode & (FMODE_READ|FMODE_WRITE)) {
UDRS->last_checked = 0;
- check_disk_change(inode->i_bdev);
+ check_disk_change(bdev);
if (UTESTF(FD_DISK_CHANGED))
goto out;
}
res = -EROFS;
- if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE)))
+ if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
goto out;
}
mutex_unlock(&open_lock);
@@ -3911,7 +3905,7 @@ static struct block_device_operations floppy_fops = {
.owner = THIS_MODULE,
.open = floppy_open,
.release = floppy_release,
- .ioctl = fd_ioctl,
+ .locked_ioctl = fd_ioctl,
.getgeo = fd_getgeo,
.media_changed = check_floppy_change,
.revalidate_disk = floppy_revalidate,
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index d3a25b027ff..3f09cd8bcc3 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -210,7 +210,7 @@ lo_do_transfer(struct loop_device *lo, int cmd,
* space operations write_begin and write_end.
*/
static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
- int bsize, loff_t pos, struct page *unused)
+ loff_t pos, struct page *unused)
{
struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
struct address_space *mapping = file->f_mapping;
@@ -302,7 +302,7 @@ static int __do_lo_send_write(struct file *file,
* filesystems.
*/
static int do_lo_send_direct_write(struct loop_device *lo,
- struct bio_vec *bvec, int bsize, loff_t pos, struct page *page)
+ struct bio_vec *bvec, loff_t pos, struct page *page)
{
ssize_t bw = __do_lo_send_write(lo->lo_backing_file,
kmap(bvec->bv_page) + bvec->bv_offset,
@@ -326,7 +326,7 @@ static int do_lo_send_direct_write(struct loop_device *lo,
* destination pages of the backing file.
*/
static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec,
- int bsize, loff_t pos, struct page *page)
+ loff_t pos, struct page *page)
{
int ret = lo_do_transfer(lo, WRITE, page, 0, bvec->bv_page,
bvec->bv_offset, bvec->bv_len, pos >> 9);
@@ -341,10 +341,9 @@ static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec,
return ret;
}
-static int lo_send(struct loop_device *lo, struct bio *bio, int bsize,
- loff_t pos)
+static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos)
{
- int (*do_lo_send)(struct loop_device *, struct bio_vec *, int, loff_t,
+ int (*do_lo_send)(struct loop_device *, struct bio_vec *, loff_t,
struct page *page);
struct bio_vec *bvec;
struct page *page = NULL;
@@ -362,7 +361,7 @@ static int lo_send(struct loop_device *lo, struct bio *bio, int bsize,
}
}
bio_for_each_segment(bvec, bio, i) {
- ret = do_lo_send(lo, bvec, bsize, pos, page);
+ ret = do_lo_send(lo, bvec, pos, page);
if (ret < 0)
break;
pos += bvec->bv_len;
@@ -478,7 +477,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset;
if (bio_rw(bio) == WRITE)
- ret = lo_send(lo, bio, lo->lo_blocksize, pos);
+ ret = lo_send(lo, bio, pos);
else
ret = lo_receive(lo, bio, lo->lo_blocksize, pos);
return ret;
@@ -652,8 +651,8 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
* This can only work if the loop device is used read-only, and if the
* new backing store is the same size and type as the old backing store.
*/
-static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
- struct block_device *bdev, unsigned int arg)
+static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
+ unsigned int arg)
{
struct file *file, *old_file;
struct inode *inode;
@@ -712,7 +711,7 @@ static inline int is_loop_device(struct file *file)
return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR;
}
-static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
+static int loop_set_fd(struct loop_device *lo, fmode_t mode,
struct block_device *bdev, unsigned int arg)
{
struct file *file, *f;
@@ -740,7 +739,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
while (is_loop_device(f)) {
struct loop_device *l;
- if (f->f_mapping->host->i_rdev == lo_file->f_mapping->host->i_rdev)
+ if (f->f_mapping->host->i_bdev == bdev)
goto out_putf;
l = f->f_mapping->host->i_bdev->bd_disk->private_data;
@@ -786,7 +785,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
goto out_putf;
}
- if (!(lo_file->f_mode & FMODE_WRITE))
+ if (!(mode & FMODE_WRITE))
lo_flags |= LO_FLAGS_READ_ONLY;
set_device_ro(bdev, (lo_flags & LO_FLAGS_READ_ONLY) != 0);
@@ -918,9 +917,11 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
memset(lo->lo_file_name, 0, LO_NAME_SIZE);
- invalidate_bdev(bdev);
+ if (bdev)
+ invalidate_bdev(bdev);
set_capacity(lo->lo_disk, 0);
- bd_set_size(bdev, 0);
+ if (bdev)
+ bd_set_size(bdev, 0);
mapping_set_gfp_mask(filp->f_mapping, gfp);
lo->lo_state = Lo_unbound;
fput(filp);
@@ -1137,22 +1138,22 @@ loop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) {
return err;
}
-static int lo_ioctl(struct inode * inode, struct file * file,
+static int lo_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
+ struct loop_device *lo = bdev->bd_disk->private_data;
int err;
mutex_lock(&lo->lo_ctl_mutex);
switch (cmd) {
case LOOP_SET_FD:
- err = loop_set_fd(lo, file, inode->i_bdev, arg);
+ err = loop_set_fd(lo, mode, bdev, arg);
break;
case LOOP_CHANGE_FD:
- err = loop_change_fd(lo, file, inode->i_bdev, arg);
+ err = loop_change_fd(lo, bdev, arg);
break;
case LOOP_CLR_FD:
- err = loop_clr_fd(lo, inode->i_bdev);
+ err = loop_clr_fd(lo, bdev);
break;
case LOOP_SET_STATUS:
err = loop_set_status_old(lo, (struct loop_info __user *) arg);
@@ -1292,10 +1293,10 @@ loop_get_status_compat(struct loop_device *lo,
return err;
}
-static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
+ struct loop_device *lo = bdev->bd_disk->private_data;
int err;
switch(cmd) {
@@ -1317,7 +1318,7 @@ static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a
arg = (unsigned long) compat_ptr(arg);
case LOOP_SET_FD:
case LOOP_CHANGE_FD:
- err = lo_ioctl(inode, file, cmd, arg);
+ err = lo_ioctl(bdev, mode, cmd, arg);
break;
default:
err = -ENOIOCTLCMD;
@@ -1327,9 +1328,9 @@ static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a
}
#endif
-static int lo_open(struct inode *inode, struct file *file)
+static int lo_open(struct block_device *bdev, fmode_t mode)
{
- struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
+ struct loop_device *lo = bdev->bd_disk->private_data;
mutex_lock(&lo->lo_ctl_mutex);
lo->lo_refcnt++;
@@ -1338,15 +1339,15 @@ static int lo_open(struct inode *inode, struct file *file)
return 0;
}
-static int lo_release(struct inode *inode, struct file *file)
+static int lo_release(struct gendisk *disk, fmode_t mode)
{
- struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
+ struct loop_device *lo = disk->private_data;
mutex_lock(&lo->lo_ctl_mutex);
--lo->lo_refcnt;
if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) && !lo->lo_refcnt)
- loop_clr_fd(lo, inode->i_bdev);
+ loop_clr_fd(lo, NULL);
mutex_unlock(&lo->lo_ctl_mutex);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 7b3351260d5..d3a91cacee8 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -391,7 +391,7 @@ static ssize_t pid_show(struct device *dev,
}
static struct device_attribute pid_attr = {
- .attr = { .name = "pid", .mode = S_IRUGO, .owner = THIS_MODULE },
+ .attr = { .name = "pid", .mode = S_IRUGO},
.show = pid_show,
};
@@ -557,10 +557,11 @@ static void do_nbd_request(struct request_queue * q)
}
}
-static int nbd_ioctl(struct inode *inode, struct file *file,
+static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct nbd_device *lo = inode->i_bdev->bd_disk->private_data;
+ struct nbd_device *lo = bdev->bd_disk->private_data;
+ struct file *file;
int error;
struct request sreq ;
struct task_struct *thread;
@@ -612,8 +613,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
error = -EINVAL;
file = fget(arg);
if (file) {
- struct block_device *bdev = inode->i_bdev;
- inode = file->f_path.dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
if (S_ISSOCK(inode->i_mode)) {
lo->file = file;
lo->sock = SOCKET_I(inode);
@@ -628,14 +628,14 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
case NBD_SET_BLKSIZE:
lo->blksize = arg;
lo->bytesize &= ~(lo->blksize-1);
- inode->i_bdev->bd_inode->i_size = lo->bytesize;
- set_blocksize(inode->i_bdev, lo->blksize);
+ bdev->bd_inode->i_size = lo->bytesize;
+ set_blocksize(bdev, lo->blksize);
set_capacity(lo->disk, lo->bytesize >> 9);
return 0;
case NBD_SET_SIZE:
lo->bytesize = arg & ~(lo->blksize-1);
- inode->i_bdev->bd_inode->i_size = lo->bytesize;
- set_blocksize(inode->i_bdev, lo->blksize);
+ bdev->bd_inode->i_size = lo->bytesize;
+ set_blocksize(bdev, lo->blksize);
set_capacity(lo->disk, lo->bytesize >> 9);
return 0;
case NBD_SET_TIMEOUT:
@@ -643,8 +643,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
return 0;
case NBD_SET_SIZE_BLOCKS:
lo->bytesize = ((u64) arg) * lo->blksize;
- inode->i_bdev->bd_inode->i_size = lo->bytesize;
- set_blocksize(inode->i_bdev, lo->blksize);
+ bdev->bd_inode->i_size = lo->bytesize;
+ set_blocksize(bdev, lo->blksize);
set_capacity(lo->disk, lo->bytesize >> 9);
return 0;
case NBD_DO_IT:
@@ -666,10 +666,10 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
if (file)
fput(file);
lo->bytesize = 0;
- inode->i_bdev->bd_inode->i_size = 0;
+ bdev->bd_inode->i_size = 0;
set_capacity(lo->disk, 0);
if (max_part > 0)
- ioctl_by_bdev(inode->i_bdev, BLKRRPART, 0);
+ ioctl_by_bdev(bdev, BLKRRPART, 0);
return lo->harderror;
case NBD_CLEAR_QUE:
/*
@@ -680,7 +680,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
return 0;
case NBD_PRINT_DEBUG:
printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n",
- inode->i_bdev->bd_disk->disk_name,
+ bdev->bd_disk->disk_name,
lo->queue_head.next, lo->queue_head.prev,
&lo->queue_head);
return 0;
@@ -691,7 +691,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
static struct block_device_operations nbd_fops =
{
.owner = THIS_MODULE,
- .ioctl = nbd_ioctl,
+ .locked_ioctl = nbd_ioctl,
};
/*
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index b8a994a2b01..e91d4b4b014 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -223,23 +223,24 @@ static int pcd_warned; /* Have we logged a phase warning ? */
/* kernel glue structures */
-static int pcd_block_open(struct inode *inode, struct file *file)
+static int pcd_block_open(struct block_device *bdev, fmode_t mode)
{
- struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data;
- return cdrom_open(&cd->info, inode, file);
+ struct pcd_unit *cd = bdev->bd_disk->private_data;
+ return cdrom_open(&cd->info, bdev, mode);
}
-static int pcd_block_release(struct inode *inode, struct file *file)
+static int pcd_block_release(struct gendisk *disk, fmode_t mode)
{
- struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data;
- return cdrom_release(&cd->info, file);
+ struct pcd_unit *cd = disk->private_data;
+ cdrom_release(&cd->info, mode);
+ return 0;
}
-static int pcd_block_ioctl(struct inode *inode, struct file *file,
+static int pcd_block_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long arg)
{
- struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data;
- return cdrom_ioctl(file, &cd->info, inode, cmd, arg);
+ struct pcd_unit *cd = bdev->bd_disk->private_data;
+ return cdrom_ioctl(&cd->info, bdev, mode, cmd, arg);
}
static int pcd_block_media_changed(struct gendisk *disk)
@@ -252,7 +253,7 @@ static struct block_device_operations pcd_bdops = {
.owner = THIS_MODULE,
.open = pcd_block_open,
.release = pcd_block_release,
- .ioctl = pcd_block_ioctl,
+ .locked_ioctl = pcd_block_ioctl,
.media_changed = pcd_block_media_changed,
};
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 5fdfa7c888c..9299455b0af 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -728,9 +728,9 @@ static int pd_special_command(struct pd_unit *disk,
/* kernel glue structures */
-static int pd_open(struct inode *inode, struct file *file)
+static int pd_open(struct block_device *bdev, fmode_t mode)
{
- struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
+ struct pd_unit *disk = bdev->bd_disk->private_data;
disk->access++;
@@ -758,10 +758,10 @@ static int pd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
-static int pd_ioctl(struct inode *inode, struct file *file,
+static int pd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
+ struct pd_unit *disk = bdev->bd_disk->private_data;
switch (cmd) {
case CDROMEJECT:
@@ -773,9 +773,9 @@ static int pd_ioctl(struct inode *inode, struct file *file,
}
}
-static int pd_release(struct inode *inode, struct file *file)
+static int pd_release(struct gendisk *p, fmode_t mode)
{
- struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
+ struct pd_unit *disk = p->private_data;
if (!--disk->access && disk->removable)
pd_special_command(disk, pd_door_unlock);
@@ -809,7 +809,7 @@ static struct block_device_operations pd_fops = {
.owner = THIS_MODULE,
.open = pd_open,
.release = pd_release,
- .ioctl = pd_ioctl,
+ .locked_ioctl = pd_ioctl,
.getgeo = pd_getgeo,
.media_changed = pd_check_media,
.revalidate_disk= pd_revalidate
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index e7fe6ca97dd..bef3b997ba3 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -201,13 +201,13 @@ module_param_array(drive3, int, NULL, 0);
#define ATAPI_READ_10 0x28
#define ATAPI_WRITE_10 0x2a
-static int pf_open(struct inode *inode, struct file *file);
+static int pf_open(struct block_device *bdev, fmode_t mode);
static void do_pf_request(struct request_queue * q);
-static int pf_ioctl(struct inode *inode, struct file *file,
+static int pf_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg);
static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo);
-static int pf_release(struct inode *inode, struct file *file);
+static int pf_release(struct gendisk *disk, fmode_t mode);
static int pf_detect(void);
static void do_pf_read(void);
@@ -266,7 +266,7 @@ static struct block_device_operations pf_fops = {
.owner = THIS_MODULE,
.open = pf_open,
.release = pf_release,
- .ioctl = pf_ioctl,
+ .locked_ioctl = pf_ioctl,
.getgeo = pf_getgeo,
.media_changed = pf_check_media,
};
@@ -296,16 +296,16 @@ static void __init pf_init_units(void)
}
}
-static int pf_open(struct inode *inode, struct file *file)
+static int pf_open(struct block_device *bdev, fmode_t mode)
{
- struct pf_unit *pf = inode->i_bdev->bd_disk->private_data;
+ struct pf_unit *pf = bdev->bd_disk->private_data;
pf_identify(pf);
if (pf->media_status == PF_NM)
return -ENODEV;
- if ((pf->media_status == PF_RO) && (file->f_mode & 2))
+ if ((pf->media_status == PF_RO) && (mode & FMODE_WRITE))
return -EROFS;
pf->access++;
@@ -333,9 +333,9 @@ static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
-static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int pf_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
{
- struct pf_unit *pf = inode->i_bdev->bd_disk->private_data;
+ struct pf_unit *pf = bdev->bd_disk->private_data;
if (cmd != CDROMEJECT)
return -EINVAL;
@@ -346,9 +346,9 @@ static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return 0;
}
-static int pf_release(struct inode *inode, struct file *file)
+static int pf_release(struct gendisk *disk, fmode_t mode)
{
- struct pf_unit *pf = inode->i_bdev->bd_disk->private_data;
+ struct pf_unit *pf = disk->private_data;
if (pf->access <= 0)
return -EINVAL;
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 5ae229656ea..1e4006e18f0 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -667,7 +667,7 @@ static int pt_open(struct inode *inode, struct file *file)
goto out;
err = -EROFS;
- if ((!(tape->flags & PT_WRITE_OK)) && (file->f_mode & 2))
+ if ((!(tape->flags & PT_WRITE_OK)) && (file->f_mode & FMODE_WRITE))
goto out;
if (!(iminor(inode) & 128))
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 195ca7c720f..f20bf359b84 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2320,7 +2320,7 @@ static int pkt_open_write(struct pktcdvd_device *pd)
/*
* called at open time.
*/
-static int pkt_open_dev(struct pktcdvd_device *pd, int write)
+static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
{
int ret;
long lba;
@@ -2332,7 +2332,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
* so bdget() can't fail.
*/
bdget(pd->bdev->bd_dev);
- if ((ret = blkdev_get(pd->bdev, FMODE_READ, O_RDONLY)))
+ if ((ret = blkdev_get(pd->bdev, FMODE_READ)))
goto out;
if ((ret = bd_claim(pd->bdev, pd)))
@@ -2381,7 +2381,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
out_unclaim:
bd_release(pd->bdev);
out_putdev:
- blkdev_put(pd->bdev);
+ blkdev_put(pd->bdev, FMODE_READ);
out:
return ret;
}
@@ -2399,7 +2399,7 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
bd_release(pd->bdev);
- blkdev_put(pd->bdev);
+ blkdev_put(pd->bdev, FMODE_READ);
pkt_shrink_pktlist(pd);
}
@@ -2411,7 +2411,7 @@ static struct pktcdvd_device *pkt_find_dev_from_minor(int dev_minor)
return pkt_devs[dev_minor];
}
-static int pkt_open(struct inode *inode, struct file *file)
+static int pkt_open(struct block_device *bdev, fmode_t mode)
{
struct pktcdvd_device *pd = NULL;
int ret;
@@ -2419,7 +2419,7 @@ static int pkt_open(struct inode *inode, struct file *file)
VPRINTK(DRIVER_NAME": entering open\n");
mutex_lock(&ctl_mutex);
- pd = pkt_find_dev_from_minor(iminor(inode));
+ pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev));
if (!pd) {
ret = -ENODEV;
goto out;
@@ -2428,20 +2428,20 @@ static int pkt_open(struct inode *inode, struct file *file)
pd->refcnt++;
if (pd->refcnt > 1) {
- if ((file->f_mode & FMODE_WRITE) &&
+ if ((mode & FMODE_WRITE) &&
!test_bit(PACKET_WRITABLE, &pd->flags)) {
ret = -EBUSY;
goto out_dec;
}
} else {
- ret = pkt_open_dev(pd, file->f_mode & FMODE_WRITE);
+ ret = pkt_open_dev(pd, mode & FMODE_WRITE);
if (ret)
goto out_dec;
/*
* needed here as well, since ext2 (among others) may change
* the blocksize at mount time
*/
- set_blocksize(inode->i_bdev, CD_FRAMESIZE);
+ set_blocksize(bdev, CD_FRAMESIZE);
}
mutex_unlock(&ctl_mutex);
@@ -2455,9 +2455,9 @@ out:
return ret;
}
-static int pkt_close(struct inode *inode, struct file *file)
+static int pkt_close(struct gendisk *disk, fmode_t mode)
{
- struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;
+ struct pktcdvd_device *pd = disk->private_data;
int ret = 0;
mutex_lock(&ctl_mutex);
@@ -2765,7 +2765,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
bdev = bdget(dev);
if (!bdev)
return -ENOMEM;
- ret = blkdev_get(bdev, FMODE_READ, O_RDONLY | O_NONBLOCK);
+ ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY);
if (ret)
return ret;
@@ -2790,19 +2790,28 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
return 0;
out_mem:
- blkdev_put(bdev);
+ blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
/* This is safe: open() is still holding a reference. */
module_put(THIS_MODULE);
return ret;
}
-static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
{
- struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;
+ struct pktcdvd_device *pd = bdev->bd_disk->private_data;
- VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode));
+ VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd,
+ MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
switch (cmd) {
+ case CDROMEJECT:
+ /*
+ * The door gets locked when the device is opened, so we
+ * have to unlock it or else the eject command fails.
+ */
+ if (pd->refcnt == 1)
+ pkt_lock_door(pd, 0);
+ /* fallthru */
/*
* forward selected CDROM ioctls to CD-ROM, for UDF
*/
@@ -2811,16 +2820,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
case CDROM_LAST_WRITTEN:
case CDROM_SEND_PACKET:
case SCSI_IOCTL_SEND_COMMAND:
- return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
-
- case CDROMEJECT:
- /*
- * The door gets locked when the device is opened, so we
- * have to unlock it or else the eject command fails.
- */
- if (pd->refcnt == 1)
- pkt_lock_door(pd, 0);
- return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
+ return __blkdev_driver_ioctl(pd->bdev, mode, cmd, arg);
default:
VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd);
@@ -2849,7 +2849,7 @@ static struct block_device_operations pktcdvd_ops = {
.owner = THIS_MODULE,
.open = pkt_open,
.release = pkt_close,
- .ioctl = pkt_ioctl,
+ .locked_ioctl = pkt_ioctl,
.media_changed = pkt_media_changed,
};
@@ -2975,7 +2975,7 @@ static int pkt_remove_dev(dev_t pkt_dev)
pkt_debugfs_dev_remove(pd);
pkt_sysfs_dev_remove(pd);
- blkdev_put(pd->bdev);
+ blkdev_put(pd->bdev, FMODE_READ|FMODE_WRITE);
remove_proc_entry(pd->name, pkt_proc);
DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name);
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 730ccea78e4..612965307ba 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -244,10 +244,10 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
int interruptible);
static void release_drive(struct floppy_state *fs);
static int fd_eject(struct floppy_state *fs);
-static int floppy_ioctl(struct inode *inode, struct file *filp,
+static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long param);
-static int floppy_open(struct inode *inode, struct file *filp);
-static int floppy_release(struct inode *inode, struct file *filp);
+static int floppy_open(struct block_device *bdev, fmode_t mode);
+static int floppy_release(struct gendisk *disk, fmode_t mode);
static int floppy_check_change(struct gendisk *disk);
static int floppy_revalidate(struct gendisk *disk);
@@ -839,10 +839,10 @@ static int fd_eject(struct floppy_state *fs)
static struct floppy_struct floppy_type =
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */
-static int floppy_ioctl(struct inode *inode, struct file *filp,
+static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long param)
{
- struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
+ struct floppy_state *fs = bdev->bd_disk->private_data;
int err;
if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
@@ -868,9 +868,9 @@ static int floppy_ioctl(struct inode *inode, struct file *filp,
return -ENOTTY;
}
-static int floppy_open(struct inode *inode, struct file *filp)
+static int floppy_open(struct block_device *bdev, fmode_t mode)
{
- struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
+ struct floppy_state *fs = bdev->bd_disk->private_data;
struct swim3 __iomem *sw = fs->swim3;
int n, err = 0;
@@ -904,17 +904,17 @@ static int floppy_open(struct inode *inode, struct file *filp)
swim3_action(fs, SETMFM);
swim3_select(fs, RELAX);
- } else if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
+ } else if (fs->ref_count == -1 || mode & FMODE_EXCL)
return -EBUSY;
- if (err == 0 && (filp->f_flags & O_NDELAY) == 0
- && (filp->f_mode & 3)) {
- check_disk_change(inode->i_bdev);
+ if (err == 0 && (mode & FMODE_NDELAY) == 0
+ && (mode & (FMODE_READ|FMODE_WRITE))) {
+ check_disk_change(bdev);
if (fs->ejected)
err = -ENXIO;
}
- if (err == 0 && (filp->f_mode & 2)) {
+ if (err == 0 && (mode & FMODE_WRITE)) {
if (fs->write_prot < 0)
fs->write_prot = swim3_readbit(fs, WRITE_PROT);
if (fs->write_prot)
@@ -930,7 +930,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
return err;
}
- if (filp->f_flags & O_EXCL)
+ if (mode & FMODE_EXCL)
fs->ref_count = -1;
else
++fs->ref_count;
@@ -938,9 +938,9 @@ static int floppy_open(struct inode *inode, struct file *filp)
return 0;
}
-static int floppy_release(struct inode *inode, struct file *filp)
+static int floppy_release(struct gendisk *disk, fmode_t mode)
{
- struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
+ struct floppy_state *fs = disk->private_data;
struct swim3 __iomem *sw = fs->swim3;
if (fs->ref_count > 0 && --fs->ref_count == 0) {
swim3_action(fs, MOTOR_OFF);
@@ -1000,7 +1000,7 @@ static int floppy_revalidate(struct gendisk *disk)
static struct block_device_operations floppy_fops = {
.open = floppy_open,
.release = floppy_release,
- .ioctl = floppy_ioctl,
+ .locked_ioctl = floppy_ioctl,
.media_changed = floppy_check_change,
.revalidate_disk= floppy_revalidate,
};
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 3a281ef11ff..fccac18d311 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -349,8 +349,6 @@ struct ub_dev {
struct work_struct reset_work;
wait_queue_head_t reset_wait;
-
- int sg_stat[6];
};
/*
@@ -685,7 +683,6 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
goto drop;
}
urq->nsg = n_elem;
- sc->sg_stat[n_elem < 5 ? n_elem : 5]++;
if (blk_pc_request(rq)) {
ub_cmd_build_packet(sc, lun, cmd, urq);
@@ -1670,10 +1667,9 @@ static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun)
* This is mostly needed to keep refcounting, but also to support
* media checks on removable media drives.
*/
-static int ub_bd_open(struct inode *inode, struct file *filp)
+static int ub_bd_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct ub_lun *lun = disk->private_data;
+ struct ub_lun *lun = bdev->bd_disk->private_data;
struct ub_dev *sc = lun->udev;
unsigned long flags;
int rc;
@@ -1687,19 +1683,19 @@ static int ub_bd_open(struct inode *inode, struct file *filp)
spin_unlock_irqrestore(&ub_lock, flags);
if (lun->removable || lun->readonly)
- check_disk_change(inode->i_bdev);
+ check_disk_change(bdev);
/*
* The sd.c considers ->media_present and ->changed not equivalent,
* under some pretty murky conditions (a failure of READ CAPACITY).
* We may need it one day.
*/
- if (lun->removable && lun->changed && !(filp->f_flags & O_NDELAY)) {
+ if (lun->removable && lun->changed && !(mode & FMODE_NDELAY)) {
rc = -ENOMEDIUM;
goto err_open;
}
- if (lun->readonly && (filp->f_mode & FMODE_WRITE)) {
+ if (lun->readonly && (mode & FMODE_WRITE)) {
rc = -EROFS;
goto err_open;
}
@@ -1713,9 +1709,8 @@ err_open:
/*
*/
-static int ub_bd_release(struct inode *inode, struct file *filp)
+static int ub_bd_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
struct ub_lun *lun = disk->private_data;
struct ub_dev *sc = lun->udev;
@@ -1726,13 +1721,13 @@ static int ub_bd_release(struct inode *inode, struct file *filp)
/*
* The ioctl interface.
*/
-static int ub_bd_ioctl(struct inode *inode, struct file *filp,
+static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct gendisk *disk = bdev->bd_disk;
void __user *usermem = (void __user *) arg;
- return scsi_cmd_ioctl(filp, disk->queue, disk, cmd, usermem);
+ return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem);
}
/*
@@ -1796,7 +1791,7 @@ static struct block_device_operations ub_bd_fops = {
.owner = THIS_MODULE,
.open = ub_bd_open,
.release = ub_bd_release,
- .ioctl = ub_bd_ioctl,
+ .locked_ioctl = ub_bd_ioctl,
.media_changed = ub_bd_media_changed,
.revalidate_disk = ub_bd_revalidate,
};
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index 1730d29e604..ecccf65dce2 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -130,15 +130,15 @@ struct viodasd_device {
/*
* External open entry point.
*/
-static int viodasd_open(struct inode *ino, struct file *fil)
+static int viodasd_open(struct block_device *bdev, fmode_t mode)
{
- struct viodasd_device *d = ino->i_bdev->bd_disk->private_data;
+ struct viodasd_device *d = bdev->bd_disk->private_data;
HvLpEvent_Rc hvrc;
struct viodasd_waitevent we;
u16 flags = 0;
if (d->read_only) {
- if ((fil != NULL) && (fil->f_mode & FMODE_WRITE))
+ if (mode & FMODE_WRITE)
return -EROFS;
flags = vioblockflags_ro;
}
@@ -179,9 +179,9 @@ static int viodasd_open(struct inode *ino, struct file *fil)
/*
* External release entry point.
*/
-static int viodasd_release(struct inode *ino, struct file *fil)
+static int viodasd_release(struct gendisk *disk, fmode_t mode)
{
- struct viodasd_device *d = ino->i_bdev->bd_disk->private_data;
+ struct viodasd_device *d = disk->private_data;
HvLpEvent_Rc hvrc;
/* Send the event to OS/400. We DON'T expect a response */
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 6ec5fc05278..85d79a02d48 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -146,11 +146,11 @@ static void do_virtblk_request(struct request_queue *q)
vblk->vq->vq_ops->kick(vblk->vq);
}
-static int virtblk_ioctl(struct inode *inode, struct file *filp,
+static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long data)
{
- return scsi_cmd_ioctl(filp, inode->i_bdev->bd_disk->queue,
- inode->i_bdev->bd_disk, cmd,
+ return scsi_cmd_ioctl(bdev->bd_disk->queue,
+ bdev->bd_disk, mode, cmd,
(void __user *)data);
}
@@ -180,7 +180,7 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
}
static struct block_device_operations virtblk_fops = {
- .ioctl = virtblk_ioctl,
+ .locked_ioctl = virtblk_ioctl,
.owner = THIS_MODULE,
.getgeo = virtblk_getgeo,
};
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 624d30f7da3..64b496fce98 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -132,7 +132,7 @@ static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
static struct block_device_operations xd_fops = {
.owner = THIS_MODULE,
- .ioctl = xd_ioctl,
+ .locked_ioctl = xd_ioctl,
.getgeo = xd_getgeo,
};
static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
@@ -343,7 +343,7 @@ static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
}
/* xd_ioctl: handle device ioctl's */
-static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
+static int xd_ioctl(struct block_device *bdev, fmode_t mode, u_int cmd, u_long arg)
{
switch (cmd) {
case HDIO_SET_DMA:
diff --git a/drivers/block/xd.h b/drivers/block/xd.h
index cffd44a2038..37cacef16e9 100644
--- a/drivers/block/xd.h
+++ b/drivers/block/xd.h
@@ -105,7 +105,7 @@ static u_char xd_detect (u_char *controller, unsigned int *address);
static u_char xd_initdrives (void (*init_drive)(u_char drive));
static void do_xd_request (struct request_queue * q);
-static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
+static int xd_ioctl (struct block_device *bdev,fmode_t mode,unsigned int cmd,unsigned long arg);
static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count);
static void xd_recalibrate (u_char drive);
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 1a50ae70f71..b220c686089 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -156,11 +156,10 @@ static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
return 0;
}
-static int blkif_ioctl(struct inode *inode, struct file *filep,
+static int blkif_ioctl(struct block_device *bdev, fmode_t mode,
unsigned command, unsigned long argument)
{
- struct blkfront_info *info =
- inode->i_bdev->bd_disk->private_data;
+ struct blkfront_info *info = bdev->bd_disk->private_data;
int i;
dev_dbg(&info->xbdev->dev, "command: 0x%x, argument: 0x%lx\n",
@@ -1014,16 +1013,16 @@ static int blkfront_is_ready(struct xenbus_device *dev)
return info->is_ready;
}
-static int blkif_open(struct inode *inode, struct file *filep)
+static int blkif_open(struct block_device *bdev, fmode_t mode)
{
- struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+ struct blkfront_info *info = bdev->bd_disk->private_data;
info->users++;
return 0;
}
-static int blkif_release(struct inode *inode, struct file *filep)
+static int blkif_release(struct gendisk *disk, fmode_t mode)
{
- struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+ struct blkfront_info *info = disk->private_data;
info->users--;
if (info->users == 0) {
/* Check whether we have been instructed to close. We will
@@ -1044,7 +1043,7 @@ static struct block_device_operations xlvbd_block_fops =
.open = blkif_open,
.release = blkif_release,
.getgeo = blkif_getgeo,
- .ioctl = blkif_ioctl,
+ .locked_ioctl = blkif_ioctl,
};
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 4a7a059ebaf..ecab9e67d47 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -870,25 +870,24 @@ static int ace_revalidate_disk(struct gendisk *gd)
return ace->id_result;
}
-static int ace_open(struct inode *inode, struct file *filp)
+static int ace_open(struct block_device *bdev, fmode_t mode)
{
- struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
+ struct ace_device *ace = bdev->bd_disk->private_data;
unsigned long flags;
dev_dbg(ace->dev, "ace_open() users=%i\n", ace->users + 1);
- filp->private_data = ace;
spin_lock_irqsave(&ace->lock, flags);
ace->users++;
spin_unlock_irqrestore(&ace->lock, flags);
- check_disk_change(inode->i_bdev);
+ check_disk_change(bdev);
return 0;
}
-static int ace_release(struct inode *inode, struct file *filp)
+static int ace_release(struct gendisk *disk, fmode_t mode)
{
- struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
+ struct ace_device *ace = disk->private_data;
unsigned long flags;
u16 val;
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index be20a67f1fa..80754cdd311 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -137,8 +137,7 @@ get_chipram( void )
return;
}
-static int
-z2_open( struct inode *inode, struct file *filp )
+static int z2_open(struct block_device *bdev, fmode_t mode)
{
int device;
int max_z2_map = ( Z2RAM_SIZE / Z2RAM_CHUNKSIZE ) *
@@ -147,7 +146,7 @@ z2_open( struct inode *inode, struct file *filp )
sizeof( z2ram_map[0] );
int rc = -ENOMEM;
- device = iminor(inode);
+ device = MINOR(bdev->bd_dev);
if ( current_device != -1 && current_device != device )
{
@@ -299,7 +298,7 @@ err_out:
}
static int
-z2_release( struct inode *inode, struct file *filp )
+z2_release(struct gendisk *disk, fmode_t mode)
{
if ( current_device == -1 )
return 0;
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index d47f2f80acc..d16b02423d6 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -973,7 +973,7 @@ static int cdrom_close_write(struct cdrom_device_info *cdi)
* is in their own interest: device control becomes a lot easier
* this way.
*/
-int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp)
+int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t mode)
{
int ret;
@@ -982,14 +982,14 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp)
/* if this was a O_NONBLOCK open and we should honor the flags,
* do a quick open without drive/disc integrity checks. */
cdi->use_count++;
- if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) {
+ if ((mode & FMODE_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) {
ret = cdi->ops->open(cdi, 1);
} else {
ret = open_for_data(cdi);
if (ret)
goto err;
cdrom_mmc3_profile(cdi);
- if (fp->f_mode & FMODE_WRITE) {
+ if (mode & FMODE_WRITE) {
ret = -EROFS;
if (cdrom_open_write(cdi))
goto err_release;
@@ -1007,7 +1007,7 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp)
cdi->name, cdi->use_count);
/* Do this on open. Don't wait for mount, because they might
not be mounting, but opening with O_NONBLOCK */
- check_disk_change(ip->i_bdev);
+ check_disk_change(bdev);
return 0;
err_release:
if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
@@ -1184,7 +1184,7 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,
return 0;
}
-int cdrom_release(struct cdrom_device_info *cdi, struct file *fp)
+void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode)
{
struct cdrom_device_ops *cdo = cdi->ops;
int opened_for_data;
@@ -1205,7 +1205,7 @@ int cdrom_release(struct cdrom_device_info *cdi, struct file *fp)
}
opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
- !(fp && fp->f_flags & O_NONBLOCK);
+ !(mode & FMODE_NDELAY);
/*
* flush cache on last write release
@@ -1219,7 +1219,6 @@ int cdrom_release(struct cdrom_device_info *cdi, struct file *fp)
cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY))
cdo->tray_move(cdi, 1);
}
- return 0;
}
static int cdrom_read_mech_status(struct cdrom_device_info *cdi,
@@ -2662,17 +2661,17 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
* these days.
* ATAPI / SCSI specific code now mainly resides in mmc_ioctl().
*/
-int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
- struct inode *ip, unsigned int cmd, unsigned long arg)
+int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
+ fmode_t mode, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int ret;
- struct gendisk *disk = ip->i_bdev->bd_disk;
+ struct gendisk *disk = bdev->bd_disk;
/*
* Try the generic SCSI command ioctl's first.
*/
- ret = scsi_cmd_ioctl(file, disk->queue, disk, cmd, argp);
+ ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
if (ret != -ENOTTY)
return ret;
@@ -2696,7 +2695,7 @@ int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
case CDROM_SELECT_DISC:
return cdrom_ioctl_select_disc(cdi, arg);
case CDROMRESET:
- return cdrom_ioctl_reset(cdi, ip->i_bdev);
+ return cdrom_ioctl_reset(cdi, bdev);
case CDROM_LOCKDOOR:
return cdrom_ioctl_lock_door(cdi, arg);
case CDROM_DEBUG:
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index d6ba77a2dd7..9aaa86b232b 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -490,14 +490,14 @@ static struct cdrom_device_ops gdrom_ops = {
.n_minors = 1,
};
-static int gdrom_bdops_open(struct inode *inode, struct file *file)
+static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode)
{
- return cdrom_open(gd.cd_info, inode, file);
+ return cdrom_open(gd.cd_info, bdev, mode);
}
-static int gdrom_bdops_release(struct inode *inode, struct file *file)
+static int gdrom_bdops_release(struct block_device *bdev, fmode_t mode)
{
- return cdrom_release(gd.cd_info, file);
+ return cdrom_release(gd.cd_info, mode);
}
static int gdrom_bdops_mediachanged(struct gendisk *disk)
@@ -505,10 +505,10 @@ static int gdrom_bdops_mediachanged(struct gendisk *disk)
return cdrom_media_changed(gd.cd_info);
}
-static int gdrom_bdops_ioctl(struct inode *inode, struct file *file,
+static int gdrom_bdops_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long arg)
{
- return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg);
+ return cdrom_ioctl(gd.cd_info, bdev, mode, cmd, arg);
}
static struct block_device_operations gdrom_bdops = {
@@ -516,7 +516,7 @@ static struct block_device_operations gdrom_bdops = {
.open = gdrom_bdops_open,
.release = gdrom_bdops_release,
.media_changed = gdrom_bdops_mediachanged,
- .ioctl = gdrom_bdops_ioctl,
+ .locked_ioctl = gdrom_bdops_ioctl,
};
static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index 031e0e1a1a3..13929356135 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -151,23 +151,24 @@ static const struct file_operations proc_viocd_operations = {
.release = single_release,
};
-static int viocd_blk_open(struct inode *inode, struct file *file)
+static int viocd_blk_open(struct block_device *bdev, fmode_t mode)
{
- struct disk_info *di = inode->i_bdev->bd_disk->private_data;
- return cdrom_open(&di->viocd_info, inode, file);
+ struct disk_info *di = bdev->bd_disk->private_data;
+ return cdrom_open(&di->viocd_info, bdev, mode);
}
-static int viocd_blk_release(struct inode *inode, struct file *file)
+static int viocd_blk_release(struct gendisk *disk, fmode_t mode)
{
- struct disk_info *di = inode->i_bdev->bd_disk->private_data;
- return cdrom_release(&di->viocd_info, file);
+ struct disk_info *di = disk->private_data;
+ cdrom_release(&di->viocd_info, mode);
+ return 0;
}
-static int viocd_blk_ioctl(struct inode *inode, struct file *file,
+static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long arg)
{
- struct disk_info *di = inode->i_bdev->bd_disk->private_data;
- return cdrom_ioctl(file, &di->viocd_info, inode, cmd, arg);
+ struct disk_info *di = bdev->bd_disk->private_data;
+ return cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg);
}
static int viocd_blk_media_changed(struct gendisk *disk)
@@ -180,7 +181,7 @@ struct block_device_operations viocd_fops = {
.owner = THIS_MODULE,
.open = viocd_blk_open,
.release = viocd_blk_release,
- .ioctl = viocd_blk_ioctl,
+ .locked_ioctl = viocd_blk_ioctl,
.media_changed = viocd_blk_media_changed,
};
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 31dcd9142d5..dc8d1a90971 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -417,6 +417,6 @@ static void __exit agp_ali_cleanup(void)
module_init(agp_ali_init);
module_exit(agp_ali_cleanup);
-MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 2812ee2b165..52f4361eb6e 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -772,6 +772,6 @@ module_init(agp_amd64_init);
module_exit(agp_amd64_cleanup);
#endif
-MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>, Andi Kleen");
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>, Andi Kleen");
module_param(agp_try_unsupported, bool, 0);
MODULE_LICENSE("GPL");
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index ae2791b926b..f1537eece07 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -561,6 +561,6 @@ static void __exit agp_ati_cleanup(void)
module_init(agp_ati_init);
module_exit(agp_ati_cleanup);
-MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 3a3cc03d401..8c617ad7497 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -349,7 +349,7 @@ static __init int agp_setup(char *s)
__setup("agp=", agp_setup);
#endif
-MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_DESCRIPTION("AGP GART driver");
MODULE_LICENSE("GPL and additional rights");
MODULE_ALIAS_MISCDEV(AGPGART_MINOR);
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 1108665913e..9cf6e9bb017 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -2390,5 +2390,5 @@ static void __exit agp_intel_cleanup(void)
module_init(agp_intel_init);
module_exit(agp_intel_cleanup);
-MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 5bbed3d79db..16acee2de11 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -1,7 +1,7 @@
/*
* Nvidia AGPGART routines.
* Based upon a 2.4 agpgart diff by the folks from NVIDIA, and hacked up
- * to work in 2.5 by Dave Jones <davej@codemonkey.org.uk>
+ * to work in 2.5 by Dave Jones <davej@redhat.com>
*/
#include <linux/module.h>
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index f2492ecf082..db60539bf67 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -20,8 +20,8 @@
#include <linux/agp_backend.h>
#include <linux/log2.h>
-#include <asm-parisc/parisc-device.h>
-#include <asm-parisc/ropes.h>
+#include <asm/parisc-device.h>
+#include <asm/ropes.h>
#include "agp.h"
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 9f4d49e1b59..d3bd243867f 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -595,4 +595,4 @@ module_init(agp_via_init);
module_exit(agp_via_cleanup);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c
index 5329d482b58..0a826d7be10 100644
--- a/drivers/char/ds1286.c
+++ b/drivers/char/ds1286.c
@@ -210,8 +210,8 @@ static int ds1286_ioctl(struct inode *inode, struct file *file,
if (sec != 0)
return -EINVAL;
- min = BIN2BCD(min);
- min = BIN2BCD(hrs);
+ min = bin2bcd(min);
+ min = bin2bcd(hrs);
spin_lock(&ds1286_lock);
rtc_write(hrs, RTC_HOURS_ALARM);
@@ -353,7 +353,7 @@ static int ds1286_proc_output(char *buf)
ds1286_get_time(&tm);
hundredth = rtc_read(RTC_HUNDREDTH_SECOND);
- BCD_TO_BIN(hundredth);
+ hundredth = bcd2bin(hundredth);
p += sprintf(p,
"rtc_time\t: %02d:%02d:%02d.%02d\n"
@@ -477,12 +477,12 @@ static void ds1286_get_time(struct rtc_time *rtc_tm)
rtc_write(save_control, RTC_CMD);
spin_unlock_irqrestore(&ds1286_lock, flags);
- BCD_TO_BIN(rtc_tm->tm_sec);
- BCD_TO_BIN(rtc_tm->tm_min);
- BCD_TO_BIN(rtc_tm->tm_hour);
- BCD_TO_BIN(rtc_tm->tm_mday);
- BCD_TO_BIN(rtc_tm->tm_mon);
- BCD_TO_BIN(rtc_tm->tm_year);
+ rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
+ rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
+ rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
+ rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
+ rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
+ rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
/*
* Account for differences between how the RTC uses the values
@@ -531,12 +531,12 @@ static int ds1286_set_time(struct rtc_time *rtc_tm)
if (yrs >= 100)
yrs -= 100;
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hrs);
- BIN_TO_BCD(day);
- BIN_TO_BCD(mon);
- BIN_TO_BCD(yrs);
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hrs = bin2bcd(hrs);
+ day = bin2bcd(day);
+ mon = bin2bcd(mon);
+ yrs = bin2bcd(yrs);
spin_lock_irqsave(&ds1286_lock, flags);
save_control = rtc_read(RTC_CMD);
@@ -572,8 +572,8 @@ static void ds1286_get_alm_time(struct rtc_time *alm_tm)
cmd = rtc_read(RTC_CMD);
spin_unlock_irqrestore(&ds1286_lock, flags);
- BCD_TO_BIN(alm_tm->tm_min);
- BCD_TO_BIN(alm_tm->tm_hour);
+ alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
+ alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
alm_tm->tm_sec = 0;
}
diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c
index c5e67a62395..170693c93c7 100644
--- a/drivers/char/ds1302.c
+++ b/drivers/char/ds1302.c
@@ -131,12 +131,12 @@ get_rtc_time(struct rtc_time *rtc_tm)
local_irq_restore(flags);
- BCD_TO_BIN(rtc_tm->tm_sec);
- BCD_TO_BIN(rtc_tm->tm_min);
- BCD_TO_BIN(rtc_tm->tm_hour);
- BCD_TO_BIN(rtc_tm->tm_mday);
- BCD_TO_BIN(rtc_tm->tm_mon);
- BCD_TO_BIN(rtc_tm->tm_year);
+ rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
+ rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
+ rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
+ rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
+ rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
+ rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
/*
* Account for differences between how the RTC uses the values
@@ -211,12 +211,12 @@ static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
else
yrs -= 1900; /* RTC (70, 71, ... 99) */
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hrs);
- BIN_TO_BCD(day);
- BIN_TO_BCD(mon);
- BIN_TO_BCD(yrs);
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hrs = bin2bcd(hrs);
+ day = bin2bcd(day);
+ mon = bin2bcd(mon);
+ yrs = bin2bcd(yrs);
lock_kernel();
local_irq_save(flags);
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 4998b2761e8..cf2461d34e5 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -2477,7 +2477,11 @@ static int pc_send_break(struct tty_struct *tty, int msec)
unsigned long flags;
if (msec == -1)
- return -EOPNOTSUPP;
+ msec = 0xFFFF;
+ else if (msec > 0xFFFE)
+ msec = 0xFFFE;
+ else if (msec < 1)
+ msec = 1;
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index f3cfb4c7612..408f5f92cb4 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -219,7 +219,7 @@ static void hpet_timer_set_irq(struct hpet_dev *devp)
for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
- if (irq >= NR_IRQS) {
+ if (irq >= nr_irqs) {
irq = HPET_MAX_IRQ;
break;
}
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index bf70450a49c..5b819b12675 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -161,7 +161,7 @@ static void hvc_console_print(struct console *co, const char *b,
}
} else {
r = cons_ops[index]->put_chars(vtermnos[index], c, i);
- if (r < 0) {
+ if (r <= 0) {
/* throw away chars on error */
i = 0;
} else if (r > 0) {
@@ -374,6 +374,9 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
+ /* cancel pending tty resize work */
+ cancel_work_sync(&hp->tty_resize);
+
/*
* Chain calls chars_in_buffer() and returns immediately if
* there is no buffered data otherwise sleeps on a wait queue
@@ -399,6 +402,9 @@ static void hvc_hangup(struct tty_struct *tty)
if (!hp)
return;
+ /* cancel pending tty resize work */
+ cancel_work_sync(&hp->tty_resize);
+
spin_lock_irqsave(&hp->lock, flags);
/*
@@ -418,8 +424,8 @@ static void hvc_hangup(struct tty_struct *tty)
spin_unlock_irqrestore(&hp->lock, flags);
- if (hp->ops->notifier_del)
- hp->ops->notifier_del(hp, hp->data);
+ if (hp->ops->notifier_hangup)
+ hp->ops->notifier_hangup(hp, hp->data);
while(temp_open_count) {
--temp_open_count;
@@ -431,7 +437,7 @@ static void hvc_hangup(struct tty_struct *tty)
* Push buffered characters whether they were just recently buffered or waiting
* on a blocked hypervisor. Call this function with hp->lock held.
*/
-static void hvc_push(struct hvc_struct *hp)
+static int hvc_push(struct hvc_struct *hp)
{
int n;
@@ -439,7 +445,7 @@ static void hvc_push(struct hvc_struct *hp)
if (n <= 0) {
if (n == 0) {
hp->do_wakeup = 1;
- return;
+ return 0;
}
/* throw away output on error; this happens when
there is no session connected to the vterm. */
@@ -450,6 +456,8 @@ static void hvc_push(struct hvc_struct *hp)
memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf);
else
hp->do_wakeup = 1;
+
+ return n;
}
static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -492,6 +500,39 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
return written;
}
+/**
+ * hvc_set_winsz() - Resize the hvc tty terminal window.
+ * @work: work structure.
+ *
+ * The routine shall not be called within an atomic context because it
+ * might sleep.
+ *
+ * Locking: hp->lock
+ */
+static void hvc_set_winsz(struct work_struct *work)
+{
+ struct hvc_struct *hp;
+ unsigned long hvc_flags;
+ struct tty_struct *tty;
+ struct winsize ws;
+
+ hp = container_of(work, struct hvc_struct, tty_resize);
+ if (!hp)
+ return;
+
+ spin_lock_irqsave(&hp->lock, hvc_flags);
+ if (!hp->tty) {
+ spin_unlock_irqrestore(&hp->lock, hvc_flags);
+ return;
+ }
+ ws = hp->ws;
+ tty = tty_kref_get(hp->tty);
+ spin_unlock_irqrestore(&hp->lock, hvc_flags);
+
+ tty_do_resize(tty, tty, &ws);
+ tty_kref_put(tty);
+}
+
/*
* This is actually a contract between the driver and the tty layer outlining
* how much write room the driver can guarantee will be sent OR BUFFERED. This
@@ -538,16 +579,20 @@ int hvc_poll(struct hvc_struct *hp)
char buf[N_INBUF] __ALIGNED__;
unsigned long flags;
int read_total = 0;
+ int written_total = 0;
spin_lock_irqsave(&hp->lock, flags);
/* Push pending writes */
if (hp->n_outbuf > 0)
- hvc_push(hp);
+ written_total = hvc_push(hp);
/* Reschedule us if still some write pending */
- if (hp->n_outbuf > 0)
+ if (hp->n_outbuf > 0) {
poll_mask |= HVC_POLL_WRITE;
+ /* If hvc_push() was not able to write, sleep a few msecs */
+ timeout = (written_total) ? 0 : MIN_TIMEOUT;
+ }
/* No tty attached, just skip */
tty = hp->tty;
@@ -632,6 +677,24 @@ int hvc_poll(struct hvc_struct *hp)
}
EXPORT_SYMBOL_GPL(hvc_poll);
+/**
+ * hvc_resize() - Update terminal window size information.
+ * @hp: HVC console pointer
+ * @ws: Terminal window size structure
+ *
+ * Stores the specified window size information in the hvc structure of @hp.
+ * The function schedule the tty resize update.
+ *
+ * Locking: Locking free; the function MUST be called holding hp->lock
+ */
+void hvc_resize(struct hvc_struct *hp, struct winsize ws)
+{
+ if ((hp->ws.ws_row != ws.ws_row) || (hp->ws.ws_col != ws.ws_col)) {
+ hp->ws = ws;
+ schedule_work(&hp->tty_resize);
+ }
+}
+
/*
* This kthread is either polling or interrupt driven. This is determined by
* calling hvc_poll() who determines whether a console adapter support
@@ -659,10 +722,6 @@ static int khvcd(void *unused)
poll_mask |= HVC_POLL_READ;
if (hvc_kicked)
continue;
- if (poll_mask & HVC_POLL_WRITE) {
- yield();
- continue;
- }
set_current_state(TASK_INTERRUPTIBLE);
if (!hvc_kicked) {
if (poll_mask == 0)
@@ -718,6 +777,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
kref_init(&hp->kref);
+ INIT_WORK(&hp->tty_resize, hvc_set_winsz);
spin_lock_init(&hp->lock);
spin_lock(&hvc_structs_lock);
@@ -743,7 +803,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
}
EXPORT_SYMBOL_GPL(hvc_alloc);
-int __devexit hvc_remove(struct hvc_struct *hp)
+int hvc_remove(struct hvc_struct *hp)
{
unsigned long flags;
struct tty_struct *tty;
@@ -796,7 +856,7 @@ static int hvc_init(void)
drv->minor_start = HVC_MINOR;
drv->type = TTY_DRIVER_TYPE_SYSTEM;
drv->init_termios = tty_std_termios;
- drv->flags = TTY_DRIVER_REAL_RAW;
+ drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(drv, &hvc_ops);
/* Always start the kthread because there can be hotplug vty adapters
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 9790201718a..8297dbc2e6e 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -27,6 +27,7 @@
#ifndef HVC_CONSOLE_H
#define HVC_CONSOLE_H
#include <linux/kref.h>
+#include <linux/tty.h>
/*
* This is the max number of console adapters that can/will be found as
@@ -56,6 +57,8 @@ struct hvc_struct {
struct hv_ops *ops;
int irq_requested;
int data;
+ struct winsize ws;
+ struct work_struct tty_resize;
struct list_head next;
struct kref kref; /* ref count & hvc_struct lifetime */
};
@@ -65,9 +68,10 @@ struct hv_ops {
int (*get_chars)(uint32_t vtermno, char *buf, int count);
int (*put_chars)(uint32_t vtermno, const char *buf, int count);
- /* Callbacks for notification. Called in open and close */
+ /* Callbacks for notification. Called in open, close and hangup */
int (*notifier_add)(struct hvc_struct *hp, int irq);
void (*notifier_del)(struct hvc_struct *hp, int irq);
+ void (*notifier_hangup)(struct hvc_struct *hp, int irq);
};
/* Register a vterm and a slot index for use as a console (console_init) */
@@ -77,15 +81,19 @@ extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data,
struct hv_ops *ops, int outbuf_size);
/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
-extern int __devexit hvc_remove(struct hvc_struct *hp);
+extern int hvc_remove(struct hvc_struct *hp);
/* data available */
int hvc_poll(struct hvc_struct *hp);
void hvc_kick(void);
+/* Resize hvc tty terminal window */
+extern void hvc_resize(struct hvc_struct *hp, struct winsize ws);
+
/* default notifier for irq based notification */
extern int notifier_add_irq(struct hvc_struct *hp, int data);
extern void notifier_del_irq(struct hvc_struct *hp, int data);
+extern void notifier_hangup_irq(struct hvc_struct *hp, int data);
#if defined(CONFIG_XMON) && defined(CONFIG_SMP)
diff --git a/drivers/char/hvc_irq.c b/drivers/char/hvc_irq.c
index 73a59cdb894..d09e5688d44 100644
--- a/drivers/char/hvc_irq.c
+++ b/drivers/char/hvc_irq.c
@@ -42,3 +42,8 @@ void notifier_del_irq(struct hvc_struct *hp, int irq)
free_irq(irq, hp);
hp->irq_requested = 0;
}
+
+void notifier_hangup_irq(struct hvc_struct *hp, int irq)
+{
+ notifier_del_irq(hp, irq);
+}
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index b71c610fe5a..b74a2f8ab90 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -202,6 +202,7 @@ static struct hv_ops hvc_get_put_ops = {
.put_chars = put_chars,
.notifier_add = notifier_add_irq,
.notifier_del = notifier_del_irq,
+ .notifier_hangup = notifier_hangup_irq,
};
static int __devinit hvc_vio_probe(struct vio_dev *vdev,
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 93f3840c168..019e0b58593 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -82,6 +82,7 @@ static struct hv_ops hvc_get_put_ops = {
.put_chars = hvc_put_chars,
.notifier_add = notifier_add_irq,
.notifier_del = notifier_del_irq,
+ .notifier_hangup = notifier_hangup_irq,
};
static int __devinit hvc_vio_probe(struct vio_dev *vdev,
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index 538ceea5e7d..eba999f8598 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -102,6 +102,7 @@ static struct hv_ops hvc_ops = {
.put_chars = write_console,
.notifier_add = notifier_add_irq,
.notifier_del = notifier_del_irq,
+ .notifier_hangup = notifier_hangup_irq,
};
static int __init xen_init(void)
diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c
index ec9d0443d92..2abd881b4cb 100644
--- a/drivers/char/ip27-rtc.c
+++ b/drivers/char/ip27-rtc.c
@@ -130,12 +130,12 @@ static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (yrs >= 100)
yrs -= 100;
- sec = BIN2BCD(sec);
- min = BIN2BCD(min);
- hrs = BIN2BCD(hrs);
- day = BIN2BCD(day);
- mon = BIN2BCD(mon);
- yrs = BIN2BCD(yrs);
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hrs = bin2bcd(hrs);
+ day = bin2bcd(day);
+ mon = bin2bcd(mon);
+ yrs = bin2bcd(yrs);
spin_lock_irq(&rtc_lock);
rtc->control |= M48T35_RTC_SET;
@@ -311,12 +311,12 @@ static void get_rtc_time(struct rtc_time *rtc_tm)
rtc->control &= ~M48T35_RTC_READ;
spin_unlock_irq(&rtc_lock);
- rtc_tm->tm_sec = BCD2BIN(rtc_tm->tm_sec);
- rtc_tm->tm_min = BCD2BIN(rtc_tm->tm_min);
- rtc_tm->tm_hour = BCD2BIN(rtc_tm->tm_hour);
- rtc_tm->tm_mday = BCD2BIN(rtc_tm->tm_mday);
- rtc_tm->tm_mon = BCD2BIN(rtc_tm->tm_mon);
- rtc_tm->tm_year = BCD2BIN(rtc_tm->tm_year);
+ rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
+ rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
+ rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
+ rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
+ rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
+ rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
/*
* Account for differences between how the RTC uses the values
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 39f6357e3b5..8054ee839b3 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -338,7 +338,7 @@ nvram_open(struct inode *inode, struct file *file)
if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
(nvram_open_mode & NVRAM_EXCL) ||
- ((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE))) {
+ ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) {
spin_unlock(&nvram_state_lock);
unlock_kernel();
return -EBUSY;
@@ -346,7 +346,7 @@ nvram_open(struct inode *inode, struct file *file)
if (file->f_flags & O_EXCL)
nvram_open_mode |= NVRAM_EXCL;
- if (file->f_mode & 2)
+ if (file->f_mode & FMODE_WRITE)
nvram_open_mode |= NVRAM_WRITE;
nvram_open_cnt++;
@@ -366,7 +366,7 @@ nvram_release(struct inode *inode, struct file *file)
/* if only one instance is open, clear the EXCL bit */
if (nvram_open_mode & NVRAM_EXCL)
nvram_open_mode &= ~NVRAM_EXCL;
- if (file->f_mode & 2)
+ if (file->f_mode & FMODE_WRITE)
nvram_open_mode &= ~NVRAM_WRITE;
spin_unlock(&nvram_state_lock);
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c
index b930de50407..3f7da8cf3a8 100644
--- a/drivers/char/pc8736x_gpio.c
+++ b/drivers/char/pc8736x_gpio.c
@@ -41,7 +41,8 @@ static u8 pc8736x_gpio_shadow[4];
#define SIO_BASE2 0x4E /* alt command-reg to check */
#define SIO_SID 0x20 /* SuperI/O ID Register */
-#define SIO_SID_VALUE 0xe9 /* Expected value in SuperI/O ID Register */
+#define SIO_SID_PC87365 0xe5 /* Expected value in ID Register for PC87365 */
+#define SIO_SID_PC87366 0xe9 /* Expected value in ID Register for PC87366 */
#define SIO_CF1 0x21 /* chip config, bit0 is chip enable */
@@ -91,13 +92,17 @@ static inline int superio_inb(int addr)
static int pc8736x_superio_present(void)
{
+ int id;
+
/* try the 2 possible values, read a hardware reg to verify */
superio_cmd = SIO_BASE1;
- if (superio_inb(SIO_SID) == SIO_SID_VALUE)
+ id = superio_inb(SIO_SID);
+ if (id == SIO_SID_PC87365 || id == SIO_SID_PC87366)
return superio_cmd;
superio_cmd = SIO_BASE2;
- if (superio_inb(SIO_SID) == SIO_SID_VALUE)
+ id = superio_inb(SIO_SID);
+ if (id == SIO_SID_PC87365 || id == SIO_SID_PC87366)
return superio_cmd;
return 0;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index c8752eaad48..705a839f179 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -558,9 +558,26 @@ struct timer_rand_state {
unsigned dont_count_entropy:1;
};
-static struct timer_rand_state input_timer_state;
static struct timer_rand_state *irq_timer_state[NR_IRQS];
+static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+ if (irq >= nr_irqs)
+ return NULL;
+
+ return irq_timer_state[irq];
+}
+
+static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+ if (irq >= nr_irqs)
+ return;
+
+ irq_timer_state[irq] = state;
+}
+
+static struct timer_rand_state input_timer_state;
+
/*
* This function adds entropy to the entropy "pool" by using timing
* delays. It uses the timer_rand_state structure to make an estimate
@@ -648,11 +665,15 @@ EXPORT_SYMBOL_GPL(add_input_randomness);
void add_interrupt_randomness(int irq)
{
- if (irq >= NR_IRQS || irq_timer_state[irq] == NULL)
+ struct timer_rand_state *state;
+
+ state = get_timer_rand_state(irq);
+
+ if (state == NULL)
return;
DEBUG_ENT("irq event %d\n", irq);
- add_timer_randomness(irq_timer_state[irq], 0x100 + irq);
+ add_timer_randomness(state, 0x100 + irq);
}
#ifdef CONFIG_BLOCK
@@ -912,7 +933,12 @@ void rand_initialize_irq(int irq)
{
struct timer_rand_state *state;
- if (irq >= NR_IRQS || irq_timer_state[irq])
+ if (irq >= nr_irqs)
+ return;
+
+ state = get_timer_rand_state(irq);
+
+ if (state)
return;
/*
@@ -921,7 +947,7 @@ void rand_initialize_irq(int irq)
*/
state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
if (state)
- irq_timer_state[irq] = state;
+ set_timer_rand_state(irq, state);
}
#ifdef CONFIG_BLOCK
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index e139372d0e6..96adf28a17e 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -65,7 +65,7 @@ static int raw_open(struct inode *inode, struct file *filp)
if (!bdev)
goto out;
igrab(bdev->bd_inode);
- err = blkdev_get(bdev, filp->f_mode, 0);
+ err = blkdev_get(bdev, filp->f_mode);
if (err)
goto out;
err = bd_claim(bdev, raw_open);
@@ -87,7 +87,7 @@ static int raw_open(struct inode *inode, struct file *filp)
out2:
bd_release(bdev);
out1:
- blkdev_put(bdev);
+ blkdev_put(bdev, filp->f_mode);
out:
mutex_unlock(&raw_mutex);
return err;
@@ -112,7 +112,7 @@ static int raw_release(struct inode *inode, struct file *filp)
mutex_unlock(&raw_mutex);
bd_release(bdev);
- blkdev_put(bdev);
+ blkdev_put(bdev, filp->f_mode);
return 0;
}
@@ -125,7 +125,7 @@ raw_ioctl(struct inode *inode, struct file *filp,
{
struct block_device *bdev = filp->private_data;
- return blkdev_ioctl(bdev->bd_inode, NULL, command, arg);
+ return blkdev_ioctl(bdev, 0, command, arg);
}
static void bind_device(struct raw_config_request *rq)
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 17683de9571..32dc89720d5 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -518,17 +518,17 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
RTC_ALWAYS_BCD) {
if (sec < 60)
- BIN_TO_BCD(sec);
+ sec = bin2bcd(sec);
else
sec = 0xff;
if (min < 60)
- BIN_TO_BCD(min);
+ min = bin2bcd(min);
else
min = 0xff;
if (hrs < 24)
- BIN_TO_BCD(hrs);
+ hrs = bin2bcd(hrs);
else
hrs = 0xff;
}
@@ -614,12 +614,12 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
|| RTC_ALWAYS_BCD) {
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hrs);
- BIN_TO_BCD(day);
- BIN_TO_BCD(mon);
- BIN_TO_BCD(yrs);
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hrs = bin2bcd(hrs);
+ day = bin2bcd(day);
+ mon = bin2bcd(mon);
+ yrs = bin2bcd(yrs);
}
save_control = CMOS_READ(RTC_CONTROL);
@@ -1099,7 +1099,7 @@ no_irq:
spin_unlock_irq(&rtc_lock);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- BCD_TO_BIN(year); /* This should never happen... */
+ year = bcd2bin(year); /* This should never happen... */
if (year < 20) {
epoch = 2000;
@@ -1352,13 +1352,13 @@ static void rtc_get_rtc_time(struct rtc_time *rtc_tm)
spin_unlock_irqrestore(&rtc_lock, flags);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BCD_TO_BIN(rtc_tm->tm_sec);
- BCD_TO_BIN(rtc_tm->tm_min);
- BCD_TO_BIN(rtc_tm->tm_hour);
- BCD_TO_BIN(rtc_tm->tm_mday);
- BCD_TO_BIN(rtc_tm->tm_mon);
- BCD_TO_BIN(rtc_tm->tm_year);
- BCD_TO_BIN(rtc_tm->tm_wday);
+ rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
+ rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
+ rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
+ rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
+ rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
+ rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
+ rtc_tm->tm_wday = bcd2bin(rtc_tm->tm_wday);
}
#ifdef CONFIG_MACH_DECSTATION
@@ -1392,9 +1392,9 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm)
spin_unlock_irq(&rtc_lock);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BCD_TO_BIN(alm_tm->tm_sec);
- BCD_TO_BIN(alm_tm->tm_min);
- BCD_TO_BIN(alm_tm->tm_hour);
+ alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
+ alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
+ alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
}
}
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 5b8d7a1aa3e..ba4e86281fb 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -2504,7 +2504,7 @@ static void __devexit sx_remove_card(struct sx_board *board,
del_timer(&board->timer);
if (pdev) {
#ifdef CONFIG_PCI
- pci_iounmap(pdev, board->base2);
+ iounmap(board->base2);
pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
#endif
} else {
@@ -2677,7 +2677,7 @@ static int __devinit sx_pci_probe(struct pci_dev *pdev,
}
board->hw_base = pci_resource_start(pdev, reg);
board->base2 =
- board->base = pci_iomap(pdev, reg, WINDOW_LEN(board));
+ board->base = ioremap_nocache(board->hw_base, WINDOW_LEN(board));
if (!board->base) {
dev_err(&pdev->dev, "ioremap failed\n");
goto err_reg;
@@ -2703,7 +2703,7 @@ static int __devinit sx_pci_probe(struct pci_dev *pdev,
return 0;
err_unmap:
- pci_iounmap(pdev, board->base2);
+ iounmap(board->base2);
err_reg:
pci_release_region(pdev, reg);
err_flag:
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index dce4cc0e695..ce0d9da52a8 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -168,7 +168,7 @@ static void sysrq_handle_show_timers(int key, struct tty_struct *tty)
static struct sysrq_key_op sysrq_show_timers_op = {
.handler = sysrq_handle_show_timers,
.help_msg = "show-all-timers(Q)",
- .action_msg = "Show Pending Timers",
+ .action_msg = "Show clockevent devices & pending hrtimers (no others)",
};
static void sysrq_handle_mountro(int key, struct tty_struct *tty)
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index e70d13defde..9c47dc48c9f 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1157,7 +1157,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
* Once all references to platform device are down to 0,
* release all allocated structures.
*/
-static void tpm_dev_release(struct device *dev)
+void tpm_dev_release(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 553b0e9d8d1..c8f8024cb40 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -90,7 +90,7 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
spin_lock_irqsave(&port->lock, flags);
if (port->tty)
tty_kref_put(port->tty);
- port->tty = tty;
+ port->tty = tty_kref_get(tty);
spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_tty_set);
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index d0f4eb6fdb7..3fb0d2c88ba 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -198,6 +198,7 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
virtio_cons.put_chars = put_chars;
virtio_cons.notifier_add = notifier_add_vio;
virtio_cons.notifier_del = notifier_del_vio;
+ virtio_cons.notifier_hangup = notifier_del_vio;
/* The first argument of hvc_alloc() is the virtual console number, so
* we use zero. The second argument is the parameter for the
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index ffe9b4e3072..54c837288d1 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -641,7 +641,7 @@ static int __devinit giu_probe(struct platform_device *dev)
}
irq = platform_get_irq(dev, 0);
- if (irq < 0 || irq >= NR_IRQS)
+ if (irq < 0 || irq >= nr_irqs)
return -EBUSY;
return cascade_irq(irq, giu_get_irq);
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 71d2ac4e3f4..c20171078d1 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -237,9 +237,12 @@ static int __init parse_pmtmr(char *arg)
if (strict_strtoul(arg, 16, &base))
return -EINVAL;
-
+#ifdef CONFIG_X86_64
+ if (base > UINT_MAX)
+ return -ERANGE;
+#endif
printk(KERN_INFO "PMTMR IOPort override: 0x%04x -> 0x%04lx\n",
- (unsigned int)pmtmr_ioport, base);
+ pmtmr_ioport, base);
pmtmr_ioport = base;
return 1;
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 5ce07b517c5..5bed73329ef 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -16,6 +16,7 @@
#include <linux/cpu.h>
#include <linux/cpuidle.h>
#include <linux/ktime.h>
+#include <linux/hrtimer.h>
#include "cpuidle.h"
@@ -56,10 +57,20 @@ static void cpuidle_idle_call(void)
if (pm_idle_old)
pm_idle_old();
else
+#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE)
+ default_idle();
+#else
local_irq_enable();
+#endif
return;
}
+ /*
+ * run any timers that can be run now, at this point
+ * before calculating the idle duration etc.
+ */
+ hrtimer_peek_ahead_timers();
+
/* ask the governor for the next state */
next_state = cpuidle_curr_governor->select(dev);
if (need_resched())
@@ -67,8 +78,11 @@ static void cpuidle_idle_call(void)
target_state = &dev->states[next_state];
/* enter the state and update stats */
- dev->last_residency = target_state->enter(dev, target_state);
dev->last_state = target_state;
+ dev->last_residency = target_state->enter(dev, target_state);
+ if (dev->last_state)
+ target_state = dev->last_state;
+
target_state->time += (unsigned long long)dev->last_residency;
target_state->usage++;
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index cd303901eb5..904e57558bb 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -48,13 +48,13 @@ config DW_DMAC
can be integrated in chips such as the Atmel AT32ap7000.
config FSL_DMA
- bool "Freescale MPC85xx/MPC83xx DMA support"
- depends on PPC
+ tristate "Freescale Elo and Elo Plus DMA support"
+ depends on FSL_SOC
select DMA_ENGINE
---help---
- Enable support for the Freescale DMA engine. Now, it support
- MPC8560/40, MPC8555, MPC8548 and MPC8641 processors.
- The MPC8349, MPC8360 is also supported.
+ Enable support for the Freescale Elo and Elo Plus DMA controllers.
+ The Elo is the DMA controller on some 82xx and 83xx parts, and the
+ Elo Plus is the DMA controller on 85xx and 86xx parts.
config MV_XOR
bool "Marvell XOR engine support"
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index a08d1970474..d1e381e35a9 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -325,7 +325,12 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan)
struct dmatest_thread *thread;
unsigned int i;
- dtc = kmalloc(sizeof(struct dmatest_chan), GFP_ATOMIC);
+ /* 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", chan->dev.bus_id);
return DMA_NAK;
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index c0059ca5834..0b95dcce447 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -370,7 +370,10 @@ static int fsl_dma_alloc_chan_resources(struct dma_chan *chan,
struct dma_client *client)
{
struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
- LIST_HEAD(tmp_list);
+
+ /* Has this channel already been allocated? */
+ if (fsl_chan->desc_pool)
+ return 1;
/* We need the descriptor to be aligned to 32bytes
* for meeting FSL DMA specification requirement.
@@ -410,6 +413,8 @@ static void fsl_dma_free_chan_resources(struct dma_chan *chan)
}
spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
dma_pool_destroy(fsl_chan->desc_pool);
+
+ fsl_chan->desc_pool = NULL;
}
static struct dma_async_tx_descriptor *
@@ -786,159 +791,29 @@ static void dma_do_tasklet(unsigned long data)
fsl_chan_ld_cleanup(fsl_chan);
}
-static void fsl_dma_callback_test(void *param)
-{
- struct fsl_dma_chan *fsl_chan = param;
- if (fsl_chan)
- dev_dbg(fsl_chan->dev, "selftest: callback is ok!\n");
-}
-
-static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan)
-{
- struct dma_chan *chan;
- int err = 0;
- dma_addr_t dma_dest, dma_src;
- dma_cookie_t cookie;
- u8 *src, *dest;
- int i;
- size_t test_size;
- struct dma_async_tx_descriptor *tx1, *tx2, *tx3;
-
- test_size = 4096;
-
- src = kmalloc(test_size * 2, GFP_KERNEL);
- if (!src) {
- dev_err(fsl_chan->dev,
- "selftest: Cannot alloc memory for test!\n");
- return -ENOMEM;
- }
-
- dest = src + test_size;
-
- for (i = 0; i < test_size; i++)
- src[i] = (u8) i;
-
- chan = &fsl_chan->common;
-
- if (fsl_dma_alloc_chan_resources(chan, NULL) < 1) {
- dev_err(fsl_chan->dev,
- "selftest: Cannot alloc resources for DMA\n");
- err = -ENODEV;
- goto out;
- }
-
- /* TX 1 */
- dma_src = dma_map_single(fsl_chan->dev, src, test_size / 2,
- DMA_TO_DEVICE);
- dma_dest = dma_map_single(fsl_chan->dev, dest, test_size / 2,
- DMA_FROM_DEVICE);
- tx1 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 2, 0);
- async_tx_ack(tx1);
-
- cookie = fsl_dma_tx_submit(tx1);
- fsl_dma_memcpy_issue_pending(chan);
- msleep(2);
-
- if (fsl_dma_is_complete(chan, cookie, NULL, NULL) != DMA_SUCCESS) {
- dev_err(fsl_chan->dev, "selftest: Time out!\n");
- err = -ENODEV;
- goto free_resources;
- }
-
- /* Test free and re-alloc channel resources */
- fsl_dma_free_chan_resources(chan);
-
- if (fsl_dma_alloc_chan_resources(chan, NULL) < 1) {
- dev_err(fsl_chan->dev,
- "selftest: Cannot alloc resources for DMA\n");
- err = -ENODEV;
- goto free_resources;
- }
-
- /* Continue to test
- * TX 2
- */
- dma_src = dma_map_single(fsl_chan->dev, src + test_size / 2,
- test_size / 4, DMA_TO_DEVICE);
- dma_dest = dma_map_single(fsl_chan->dev, dest + test_size / 2,
- test_size / 4, DMA_FROM_DEVICE);
- tx2 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 4, 0);
- async_tx_ack(tx2);
-
- /* TX 3 */
- dma_src = dma_map_single(fsl_chan->dev, src + test_size * 3 / 4,
- test_size / 4, DMA_TO_DEVICE);
- dma_dest = dma_map_single(fsl_chan->dev, dest + test_size * 3 / 4,
- test_size / 4, DMA_FROM_DEVICE);
- tx3 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 4, 0);
- async_tx_ack(tx3);
-
- /* Interrupt tx test */
- tx1 = fsl_dma_prep_interrupt(chan, 0);
- async_tx_ack(tx1);
- cookie = fsl_dma_tx_submit(tx1);
-
- /* Test exchanging the prepared tx sort */
- cookie = fsl_dma_tx_submit(tx3);
- cookie = fsl_dma_tx_submit(tx2);
-
- if (dma_has_cap(DMA_INTERRUPT, ((struct fsl_dma_device *)
- dev_get_drvdata(fsl_chan->dev->parent))->common.cap_mask)) {
- tx3->callback = fsl_dma_callback_test;
- tx3->callback_param = fsl_chan;
- }
- fsl_dma_memcpy_issue_pending(chan);
- msleep(2);
-
- if (fsl_dma_is_complete(chan, cookie, NULL, NULL) != DMA_SUCCESS) {
- dev_err(fsl_chan->dev, "selftest: Time out!\n");
- err = -ENODEV;
- goto free_resources;
- }
-
- err = memcmp(src, dest, test_size);
- if (err) {
- for (i = 0; (*(src + i) == *(dest + i)) && (i < test_size);
- i++);
- dev_err(fsl_chan->dev, "selftest: Test failed, data %d/%ld is "
- "error! src 0x%x, dest 0x%x\n",
- i, (long)test_size, *(src + i), *(dest + i));
- }
-
-free_resources:
- fsl_dma_free_chan_resources(chan);
-out:
- kfree(src);
- return err;
-}
-
-static int __devinit of_fsl_dma_chan_probe(struct of_device *dev,
- const struct of_device_id *match)
+static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev,
+ struct device_node *node, u32 feature, const char *compatible)
{
- struct fsl_dma_device *fdev;
struct fsl_dma_chan *new_fsl_chan;
int err;
- fdev = dev_get_drvdata(dev->dev.parent);
- BUG_ON(!fdev);
-
/* alloc channel */
new_fsl_chan = kzalloc(sizeof(struct fsl_dma_chan), GFP_KERNEL);
if (!new_fsl_chan) {
- dev_err(&dev->dev, "No free memory for allocating "
+ dev_err(fdev->dev, "No free memory for allocating "
"dma channels!\n");
return -ENOMEM;
}
/* get dma channel register base */
- err = of_address_to_resource(dev->node, 0, &new_fsl_chan->reg);
+ err = of_address_to_resource(node, 0, &new_fsl_chan->reg);
if (err) {
- dev_err(&dev->dev, "Can't get %s property 'reg'\n",
- dev->node->full_name);
+ dev_err(fdev->dev, "Can't get %s property 'reg'\n",
+ node->full_name);
goto err_no_reg;
}
- new_fsl_chan->feature = *(u32 *)match->data;
+ new_fsl_chan->feature = feature;
if (!fdev->feature)
fdev->feature = new_fsl_chan->feature;
@@ -948,13 +823,13 @@ static int __devinit of_fsl_dma_chan_probe(struct of_device *dev,
*/
WARN_ON(fdev->feature != new_fsl_chan->feature);
- new_fsl_chan->dev = &dev->dev;
+ new_fsl_chan->dev = &new_fsl_chan->common.dev;
new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start,
new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1);
new_fsl_chan->id = ((new_fsl_chan->reg.start - 0x100) & 0xfff) >> 7;
if (new_fsl_chan->id > FSL_DMA_MAX_CHANS_PER_DEVICE) {
- dev_err(&dev->dev, "There is no %d channel!\n",
+ dev_err(fdev->dev, "There is no %d channel!\n",
new_fsl_chan->id);
err = -EINVAL;
goto err_no_chan;
@@ -988,29 +863,23 @@ static int __devinit of_fsl_dma_chan_probe(struct of_device *dev,
&fdev->common.channels);
fdev->common.chancnt++;
- new_fsl_chan->irq = irq_of_parse_and_map(dev->node, 0);
+ new_fsl_chan->irq = irq_of_parse_and_map(node, 0);
if (new_fsl_chan->irq != NO_IRQ) {
err = request_irq(new_fsl_chan->irq,
&fsl_dma_chan_do_interrupt, IRQF_SHARED,
"fsldma-channel", new_fsl_chan);
if (err) {
- dev_err(&dev->dev, "DMA channel %s request_irq error "
- "with return %d\n", dev->node->full_name, err);
+ dev_err(fdev->dev, "DMA channel %s request_irq error "
+ "with return %d\n", node->full_name, err);
goto err_no_irq;
}
}
- err = fsl_dma_self_test(new_fsl_chan);
- if (err)
- goto err_self_test;
-
- dev_info(&dev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id,
- match->compatible, new_fsl_chan->irq);
+ dev_info(fdev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id,
+ compatible, new_fsl_chan->irq);
return 0;
-err_self_test:
- free_irq(new_fsl_chan->irq, new_fsl_chan);
err_no_irq:
list_del(&new_fsl_chan->common.device_node);
err_no_chan:
@@ -1020,38 +889,20 @@ err_no_reg:
return err;
}
-const u32 mpc8540_dma_ip_feature = FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN;
-const u32 mpc8349_dma_ip_feature = FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN;
-
-static struct of_device_id of_fsl_dma_chan_ids[] = {
- {
- .compatible = "fsl,eloplus-dma-channel",
- .data = (void *)&mpc8540_dma_ip_feature,
- },
- {
- .compatible = "fsl,elo-dma-channel",
- .data = (void *)&mpc8349_dma_ip_feature,
- },
- {}
-};
-
-static struct of_platform_driver of_fsl_dma_chan_driver = {
- .name = "of-fsl-dma-channel",
- .match_table = of_fsl_dma_chan_ids,
- .probe = of_fsl_dma_chan_probe,
-};
-
-static __init int of_fsl_dma_chan_init(void)
+static void fsl_dma_chan_remove(struct fsl_dma_chan *fchan)
{
- return of_register_platform_driver(&of_fsl_dma_chan_driver);
+ free_irq(fchan->irq, fchan);
+ list_del(&fchan->common.device_node);
+ iounmap(fchan->reg_base);
+ kfree(fchan);
}
static int __devinit of_fsl_dma_probe(struct of_device *dev,
const struct of_device_id *match)
{
int err;
- unsigned int irq;
struct fsl_dma_device *fdev;
+ struct device_node *child;
fdev = kzalloc(sizeof(struct fsl_dma_device), GFP_KERNEL);
if (!fdev) {
@@ -1085,9 +936,9 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
fdev->common.dev = &dev->dev;
- irq = irq_of_parse_and_map(dev->node, 0);
- if (irq != NO_IRQ) {
- err = request_irq(irq, &fsl_dma_do_interrupt, IRQF_SHARED,
+ fdev->irq = irq_of_parse_and_map(dev->node, 0);
+ if (fdev->irq != NO_IRQ) {
+ err = request_irq(fdev->irq, &fsl_dma_do_interrupt, IRQF_SHARED,
"fsldma-device", fdev);
if (err) {
dev_err(&dev->dev, "DMA device request_irq error "
@@ -1097,7 +948,21 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
}
dev_set_drvdata(&(dev->dev), fdev);
- of_platform_bus_probe(dev->node, of_fsl_dma_chan_ids, &dev->dev);
+
+ /* We cannot use of_platform_bus_probe() because there is no
+ * of_platform_bus_remove. Instead, we manually instantiate every DMA
+ * channel object.
+ */
+ for_each_child_of_node(dev->node, child) {
+ if (of_device_is_compatible(child, "fsl,eloplus-dma-channel"))
+ fsl_dma_chan_probe(fdev, child,
+ FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN,
+ "fsl,eloplus-dma-channel");
+ if (of_device_is_compatible(child, "fsl,elo-dma-channel"))
+ fsl_dma_chan_probe(fdev, child,
+ FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN,
+ "fsl,elo-dma-channel");
+ }
dma_async_device_register(&fdev->common);
return 0;
@@ -1109,6 +974,30 @@ err_no_reg:
return err;
}
+static int of_fsl_dma_remove(struct of_device *of_dev)
+{
+ struct fsl_dma_device *fdev;
+ unsigned int i;
+
+ fdev = dev_get_drvdata(&of_dev->dev);
+
+ dma_async_device_unregister(&fdev->common);
+
+ for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++)
+ if (fdev->chan[i])
+ fsl_dma_chan_remove(fdev->chan[i]);
+
+ if (fdev->irq != NO_IRQ)
+ free_irq(fdev->irq, fdev);
+
+ iounmap(fdev->reg_base);
+
+ kfree(fdev);
+ dev_set_drvdata(&of_dev->dev, NULL);
+
+ return 0;
+}
+
static struct of_device_id of_fsl_dma_ids[] = {
{ .compatible = "fsl,eloplus-dma", },
{ .compatible = "fsl,elo-dma", },
@@ -1116,15 +1005,32 @@ static struct of_device_id of_fsl_dma_ids[] = {
};
static struct of_platform_driver of_fsl_dma_driver = {
- .name = "of-fsl-dma",
+ .name = "fsl-elo-dma",
.match_table = of_fsl_dma_ids,
.probe = of_fsl_dma_probe,
+ .remove = of_fsl_dma_remove,
};
static __init int of_fsl_dma_init(void)
{
- return of_register_platform_driver(&of_fsl_dma_driver);
+ int ret;
+
+ pr_info("Freescale Elo / Elo Plus DMA driver\n");
+
+ ret = of_register_platform_driver(&of_fsl_dma_driver);
+ if (ret)
+ pr_err("fsldma: failed to register platform driver\n");
+
+ return ret;
+}
+
+static void __exit of_fsl_dma_exit(void)
+{
+ of_unregister_platform_driver(&of_fsl_dma_driver);
}
-subsys_initcall(of_fsl_dma_chan_init);
subsys_initcall(of_fsl_dma_init);
+module_exit(of_fsl_dma_exit);
+
+MODULE_DESCRIPTION("Freescale Elo / Elo Plus DMA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 6faf07ba0d0..4f21a512d84 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -114,6 +114,7 @@ struct fsl_dma_device {
struct dma_device common;
struct fsl_dma_chan *chan[FSL_DMA_MAX_CHANS_PER_DEVICE];
u32 feature; /* The same as DMA channels */
+ int irq; /* Channel IRQ */
};
/* Define macros for fsl_dma_chan->feature property */
diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c
index bc8c6e3470c..43b8cefad2c 100644
--- a/drivers/dma/ioat_dma.c
+++ b/drivers/dma/ioat_dma.c
@@ -171,6 +171,9 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET);
xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale));
+#if CONFIG_I7300_IDLE_IOAT_CHANNEL
+ device->common.chancnt--;
+#endif
for (i = 0; i < device->common.chancnt; i++) {
ioat_chan = kzalloc(sizeof(*ioat_chan), GFP_KERNEL);
if (!ioat_chan) {
@@ -971,11 +974,9 @@ static struct ioat_desc_sw *ioat_dma_get_next_descriptor(
switch (ioat_chan->device->version) {
case IOAT_VER_1_2:
return ioat1_dma_get_next_descriptor(ioat_chan);
- break;
case IOAT_VER_2_0:
case IOAT_VER_3_0:
return ioat2_dma_get_next_descriptor(ioat_chan);
- break;
}
return NULL;
}
diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c
index 0e024fe2d8c..887072f5dc8 100644
--- a/drivers/edac/cell_edac.c
+++ b/drivers/edac/cell_edac.c
@@ -142,7 +142,7 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
csrow->nr_pages = (r.end - r.start + 1) >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
csrow->mtype = MEM_XDR;
- csrow->edac_mode = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+ csrow->edac_mode = EDAC_SECDED;
dev_dbg(mci->dev,
"Initialized on node %d, chanmask=0x%x,"
" first_page=0x%lx, nr_pages=0x%x\n",
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index deb154aa47c..4353414a0b7 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -732,7 +732,6 @@ static int __init ibft_create_attribute(struct ibft_kobject *kobj_data,
attr->attr.name = name;
attr->attr.mode = S_IRUSR;
- attr->attr.owner = THIS_MODULE;
attr->hdr = hdr;
attr->show = show;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index dbd42d6c93a..7f2ee27fe76 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -127,6 +127,13 @@ config GPIO_PCF857X
This driver provides an in-kernel interface to those GPIOs using
platform-neutral GPIO calls.
+config GPIO_TWL4030
+ tristate "TWL4030, TWL5030, and TPS659x0 GPIOs"
+ depends on TWL4030_CORE
+ help
+ Say yes here to access the GPIO signals of various multi-function
+ power management chips from Texas Instruments.
+
comment "PCI GPIO expanders:"
config GPIO_BT8XX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 01b4bbde195..6aafdeb9ad0 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_GPIO_MAX732X) += max732x.o
obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
+obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o
obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 9112830107a..faa1cc66e9c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -248,7 +248,7 @@ static ssize_t gpio_value_show(struct device *dev,
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else
- status = sprintf(buf, "%d\n", gpio_get_value_cansleep(gpio));
+ status = sprintf(buf, "%d\n", !!gpio_get_value_cansleep(gpio));
mutex_unlock(&sysfs_lock);
return status;
@@ -1105,7 +1105,7 @@ int gpio_get_value_cansleep(unsigned gpio)
might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio);
- return chip->get(chip, gpio - chip->base);
+ return chip->get ? chip->get(chip, gpio - chip->base) : 0;
}
EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
@@ -1143,7 +1143,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
if (!is_out) {
int irq = gpio_to_irq(gpio);
- struct irq_desc *desc = irq_desc + irq;
+ struct irq_desc *desc = irq_to_desc(irq);
/* This races with request_irq(), set_irq_type(),
* and set_irq_wake() ... but those are "rare".
diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c
new file mode 100644
index 00000000000..37d3eec8730
--- /dev/null
+++ b/drivers/gpio/twl4030-gpio.c
@@ -0,0 +1,521 @@
+/*
+ * twl4030_gpio.c -- access to GPIOs on TWL4030/TPS659x0 chips
+ *
+ * Copyright (C) 2006-2007 Texas Instruments, Inc.
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Code re-arranged and cleaned up by:
+ * Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * Initial Code:
+ * Andy Lowe / Nishanth Menon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * The GPIO "subchip" supports 18 GPIOs which can be configured as
+ * inputs or outputs, with pullups or pulldowns on each pin. Each
+ * GPIO can trigger interrupts on either or both edges.
+ *
+ * GPIO interrupts can be fed to either of two IRQ lines; this is
+ * intended to support multiple hosts.
+ *
+ * There are also two LED pins used sometimes as output-only GPIOs.
+ */
+
+
+static struct gpio_chip twl_gpiochip;
+static int twl4030_gpio_irq_base;
+
+/* genirq interfaces are not available to modules */
+#ifdef MODULE
+#define is_module() true
+#else
+#define is_module() false
+#endif
+
+/* GPIO_CTRL Fields */
+#define MASK_GPIO_CTRL_GPIO0CD1 BIT(0)
+#define MASK_GPIO_CTRL_GPIO1CD2 BIT(1)
+#define MASK_GPIO_CTRL_GPIO_ON BIT(2)
+
+/* Mask for GPIO registers when aggregated into a 32-bit integer */
+#define GPIO_32_MASK 0x0003ffff
+
+/* Data structures */
+static DEFINE_MUTEX(gpio_lock);
+
+/* store usage of each GPIO. - each bit represents one GPIO */
+static unsigned int gpio_usage_count;
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * To configure TWL4030 GPIO module registers
+ */
+static inline int gpio_twl4030_write(u8 address, u8 data)
+{
+ return twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * LED register offsets (use TWL4030_MODULE_{LED,PWMA,PWMB}))
+ * PWMs A and B are dedicated to LEDs A and B, respectively.
+ */
+
+#define TWL4030_LED_LEDEN 0x0
+
+/* LEDEN bits */
+#define LEDEN_LEDAON BIT(0)
+#define LEDEN_LEDBON BIT(1)
+#define LEDEN_LEDAEXT BIT(2)
+#define LEDEN_LEDBEXT BIT(3)
+#define LEDEN_LEDAPWM BIT(4)
+#define LEDEN_LEDBPWM BIT(5)
+#define LEDEN_PWM_LENGTHA BIT(6)
+#define LEDEN_PWM_LENGTHB BIT(7)
+
+#define TWL4030_PWMx_PWMxON 0x0
+#define TWL4030_PWMx_PWMxOFF 0x1
+
+#define PWMxON_LENGTH BIT(7)
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * To read a TWL4030 GPIO module register
+ */
+static inline int gpio_twl4030_read(u8 address)
+{
+ u8 data;
+ int ret = 0;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
+ return (ret < 0) ? ret : data;
+}
+
+/*----------------------------------------------------------------------*/
+
+static u8 cached_leden; /* protected by gpio_lock */
+
+/* The LED lines are open drain outputs ... a FET pulls to GND, so an
+ * external pullup is needed. We could also expose the integrated PWM
+ * as a LED brightness control; we initialize it as "always on".
+ */
+static void twl4030_led_set_value(int led, int value)
+{
+ u8 mask = LEDEN_LEDAON | LEDEN_LEDAPWM;
+ int status;
+
+ if (led)
+ mask <<= 1;
+
+ mutex_lock(&gpio_lock);
+ if (value)
+ cached_leden &= ~mask;
+ else
+ cached_leden |= mask;
+ status = twl4030_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
+ TWL4030_LED_LEDEN);
+ mutex_unlock(&gpio_lock);
+}
+
+static int twl4030_set_gpio_direction(int gpio, int is_input)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
+ u8 reg = 0;
+ u8 base = REG_GPIODATADIR1 + d_bnk;
+ int ret = 0;
+
+ mutex_lock(&gpio_lock);
+ ret = gpio_twl4030_read(base);
+ if (ret >= 0) {
+ if (is_input)
+ reg = ret & ~d_msk;
+ else
+ reg = ret | d_msk;
+
+ ret = gpio_twl4030_write(base, reg);
+ }
+ mutex_unlock(&gpio_lock);
+ return ret;
+}
+
+static int twl4030_set_gpio_dataout(int gpio, int enable)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
+ u8 base = 0;
+
+ if (enable)
+ base = REG_SETGPIODATAOUT1 + d_bnk;
+ else
+ base = REG_CLEARGPIODATAOUT1 + d_bnk;
+
+ return gpio_twl4030_write(base, d_msk);
+}
+
+static int twl4030_get_gpio_datain(int gpio)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_off = gpio & 0x7;
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & BIT(gpio))))
+ return -EPERM;
+
+ base = REG_GPIODATAIN1 + d_bnk;
+ ret = gpio_twl4030_read(base);
+ if (ret > 0)
+ ret = (ret >> d_off) & 0x1;
+
+ return ret;
+}
+
+/*
+ * Configure debounce timing value for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_debounce(int gpio, int enable)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
+ u8 reg = 0;
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & BIT(gpio))))
+ return -EPERM;
+
+ base = REG_GPIO_DEBEN1 + d_bnk;
+ mutex_lock(&gpio_lock);
+ ret = gpio_twl4030_read(base);
+ if (ret >= 0) {
+ if (enable)
+ reg = ret | d_msk;
+ else
+ reg = ret & ~d_msk;
+
+ ret = gpio_twl4030_write(base, reg);
+ }
+ mutex_unlock(&gpio_lock);
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_set_gpio_debounce);
+
+/*----------------------------------------------------------------------*/
+
+static int twl_request(struct gpio_chip *chip, unsigned offset)
+{
+ int status = 0;
+
+ mutex_lock(&gpio_lock);
+
+ /* Support the two LED outputs as output-only GPIOs. */
+ if (offset >= TWL4030_GPIO_MAX) {
+ u8 ledclr_mask = LEDEN_LEDAON | LEDEN_LEDAEXT
+ | LEDEN_LEDAPWM | LEDEN_PWM_LENGTHA;
+ u8 module = TWL4030_MODULE_PWMA;
+
+ offset -= TWL4030_GPIO_MAX;
+ if (offset) {
+ ledclr_mask <<= 1;
+ module = TWL4030_MODULE_PWMB;
+ }
+
+ /* initialize PWM to always-drive */
+ status = twl4030_i2c_write_u8(module, 0x7f,
+ TWL4030_PWMx_PWMxOFF);
+ if (status < 0)
+ goto done;
+ status = twl4030_i2c_write_u8(module, 0x7f,
+ TWL4030_PWMx_PWMxON);
+ if (status < 0)
+ goto done;
+
+ /* init LED to not-driven (high) */
+ module = TWL4030_MODULE_LED;
+ status = twl4030_i2c_read_u8(module, &cached_leden,
+ TWL4030_LED_LEDEN);
+ if (status < 0)
+ goto done;
+ cached_leden &= ~ledclr_mask;
+ status = twl4030_i2c_write_u8(module, cached_leden,
+ TWL4030_LED_LEDEN);
+ if (status < 0)
+ goto done;
+
+ status = 0;
+ goto done;
+ }
+
+ /* on first use, turn GPIO module "on" */
+ if (!gpio_usage_count) {
+ struct twl4030_gpio_platform_data *pdata;
+ u8 value = MASK_GPIO_CTRL_GPIO_ON;
+
+ /* optionally have the first two GPIOs switch vMMC1
+ * and vMMC2 power supplies based on card presence.
+ */
+ pdata = chip->dev->platform_data;
+ value |= pdata->mmc_cd & 0x03;
+
+ status = gpio_twl4030_write(REG_GPIO_CTRL, value);
+ }
+
+ if (!status)
+ gpio_usage_count |= (0x1 << offset);
+
+done:
+ mutex_unlock(&gpio_lock);
+ return status;
+}
+
+static void twl_free(struct gpio_chip *chip, unsigned offset)
+{
+ if (offset >= TWL4030_GPIO_MAX) {
+ twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1);
+ return;
+ }
+
+ mutex_lock(&gpio_lock);
+
+ gpio_usage_count &= ~BIT(offset);
+
+ /* on last use, switch off GPIO module */
+ if (!gpio_usage_count)
+ gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
+
+ mutex_unlock(&gpio_lock);
+}
+
+static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ return (offset < TWL4030_GPIO_MAX)
+ ? twl4030_set_gpio_direction(offset, 1)
+ : -EINVAL;
+}
+
+static int twl_get(struct gpio_chip *chip, unsigned offset)
+{
+ int status = 0;
+
+ if (offset < TWL4030_GPIO_MAX)
+ status = twl4030_get_gpio_datain(offset);
+ else if (offset == TWL4030_GPIO_MAX)
+ status = cached_leden & LEDEN_LEDAON;
+ else
+ status = cached_leden & LEDEN_LEDBON;
+ return (status < 0) ? 0 : status;
+}
+
+static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+ if (offset < TWL4030_GPIO_MAX) {
+ twl4030_set_gpio_dataout(offset, value);
+ return twl4030_set_gpio_direction(offset, 0);
+ } else {
+ twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
+ return 0;
+ }
+}
+
+static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ if (offset < TWL4030_GPIO_MAX)
+ twl4030_set_gpio_dataout(offset, value);
+ else
+ twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
+}
+
+static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX))
+ ? (twl4030_gpio_irq_base + offset)
+ : -EINVAL;
+}
+
+static struct gpio_chip twl_gpiochip = {
+ .label = "twl4030",
+ .owner = THIS_MODULE,
+ .request = twl_request,
+ .free = twl_free,
+ .direction_input = twl_direction_in,
+ .get = twl_get,
+ .direction_output = twl_direction_out,
+ .set = twl_set,
+ .to_irq = twl_to_irq,
+ .can_sleep = 1,
+};
+
+/*----------------------------------------------------------------------*/
+
+static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs)
+{
+ u8 message[6];
+ unsigned i, gpio_bit;
+
+ /* For most pins, a pulldown was enabled by default.
+ * We should have data that's specific to this board.
+ */
+ for (gpio_bit = 1, i = 1; i < 6; i++) {
+ u8 bit_mask;
+ unsigned j;
+
+ for (bit_mask = 0, j = 0; j < 8; j += 2, gpio_bit <<= 1) {
+ if (ups & gpio_bit)
+ bit_mask |= 1 << (j + 1);
+ else if (downs & gpio_bit)
+ bit_mask |= 1 << (j + 0);
+ }
+ message[i] = bit_mask;
+ }
+
+ return twl4030_i2c_write(TWL4030_MODULE_GPIO, message,
+ REG_GPIOPUPDCTR1, 5);
+}
+
+static int gpio_twl4030_remove(struct platform_device *pdev);
+
+static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
+{
+ struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+
+ /* maybe setup IRQs */
+ if (pdata->irq_base) {
+ if (is_module()) {
+ dev_err(&pdev->dev,
+ "can't dispatch IRQs from modules\n");
+ goto no_irqs;
+ }
+ ret = twl4030_sih_setup(TWL4030_MODULE_GPIO);
+ if (ret < 0)
+ return ret;
+ WARN_ON(ret != pdata->irq_base);
+ twl4030_gpio_irq_base = ret;
+ }
+
+no_irqs:
+ /*
+ * NOTE: boards may waste power if they don't set pullups
+ * and pulldowns correctly ... default for non-ULPI pins is
+ * pulldown, and some other pins may have external pullups
+ * or pulldowns. Careful!
+ */
+ ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
+ if (ret)
+ dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
+ pdata->pullups, pdata->pulldowns,
+ ret);
+
+ twl_gpiochip.base = pdata->gpio_base;
+ twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
+ twl_gpiochip.dev = &pdev->dev;
+
+ /* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
+ * is (still) clear if use_leds is set.
+ */
+ if (pdata->use_leds)
+ twl_gpiochip.ngpio += 2;
+
+ ret = gpiochip_add(&twl_gpiochip);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "could not register gpiochip, %d\n",
+ ret);
+ twl_gpiochip.ngpio = 0;
+ gpio_twl4030_remove(pdev);
+ } else if (pdata->setup) {
+ int status;
+
+ status = pdata->setup(&pdev->dev,
+ pdata->gpio_base, TWL4030_GPIO_MAX);
+ if (status)
+ dev_dbg(&pdev->dev, "setup --> %d\n", status);
+ }
+
+ return ret;
+}
+
+static int __devexit gpio_twl4030_remove(struct platform_device *pdev)
+{
+ struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+ int status;
+
+ if (pdata->teardown) {
+ status = pdata->teardown(&pdev->dev,
+ pdata->gpio_base, TWL4030_GPIO_MAX);
+ if (status) {
+ dev_dbg(&pdev->dev, "teardown --> %d\n", status);
+ return status;
+ }
+ }
+
+ status = gpiochip_remove(&twl_gpiochip);
+ if (status < 0)
+ return status;
+
+ if (is_module())
+ return 0;
+
+ /* REVISIT no support yet for deregistering all the IRQs */
+ WARN_ON(1);
+ return -EIO;
+}
+
+/* Note: this hardware lives inside an I2C-based multi-function device. */
+MODULE_ALIAS("platform:twl4030_gpio");
+
+static struct platform_driver gpio_twl4030_driver = {
+ .driver.name = "twl4030_gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = gpio_twl4030_probe,
+ .remove = __devexit_p(gpio_twl4030_remove),
+};
+
+static int __init gpio_twl4030_init(void)
+{
+ return platform_driver_register(&gpio_twl4030_driver);
+}
+subsys_initcall(gpio_twl4030_init);
+
+static void __exit gpio_twl4030_exit(void)
+{
+ platform_driver_unregister(&gpio_twl4030_driver);
+}
+module_exit(gpio_twl4030_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("GPIO interface for TWL4030");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 610d6fd5bb5..a8b33c2ec8d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -6,7 +6,7 @@
#
menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
- depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG
+ depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU
help
Kernel-level support for the Direct Rendering Infrastructure (DRI)
introduced in XFree86 4.0. If you say Y here, you need to select
@@ -87,6 +87,7 @@ config DRM_MGA
config DRM_SIS
tristate "SiS video cards"
depends on DRM && AGP
+ depends on FB_SIS || FB_SIS=n
help
Choose this option if you have a SiS 630 or compatible video
chipset. If M is selected the module will be called sis. AGP
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e9f9a97ae00..74da99495e2 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -4,8 +4,9 @@
ccflags-y := -Iinclude/drm
-drm-y := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
- drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
+drm-y := drm_auth.o drm_bufs.o drm_cache.o \
+ drm_context.o drm_dma.o drm_drawable.o \
+ drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c
index aefa5ac4c0b..3d33b8252b5 100644
--- a/drivers/gpu/drm/drm_agpsupport.c
+++ b/drivers/gpu/drm/drm_agpsupport.c
@@ -33,6 +33,7 @@
#include "drmP.h"
#include <linux/module.h>
+#include <asm/agp.h>
#if __OS_HAS_AGP
@@ -452,4 +453,53 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
return agp_unbind_memory(handle);
}
-#endif /* __OS_HAS_AGP */
+/**
+ * Binds a collection of pages into AGP memory at the given offset, returning
+ * the AGP memory structure containing them.
+ *
+ * No reference is held on the pages during this time -- it is up to the
+ * caller to handle that.
+ */
+DRM_AGP_MEM *
+drm_agp_bind_pages(struct drm_device *dev,
+ struct page **pages,
+ unsigned long num_pages,
+ uint32_t gtt_offset,
+ u32 type)
+{
+ DRM_AGP_MEM *mem;
+ int ret, i;
+
+ DRM_DEBUG("\n");
+
+ mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages,
+ type);
+ if (mem == NULL) {
+ DRM_ERROR("Failed to allocate memory for %ld pages\n",
+ num_pages);
+ return NULL;
+ }
+
+ for (i = 0; i < num_pages; i++)
+ mem->memory[i] = phys_to_gart(page_to_phys(pages[i]));
+ mem->page_count = num_pages;
+
+ mem->is_flushed = true;
+ ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
+ if (ret != 0) {
+ DRM_ERROR("Failed to bind AGP memory: %d\n", ret);
+ agp_free_memory(mem);
+ return NULL;
+ }
+
+ return mem;
+}
+EXPORT_SYMBOL(drm_agp_bind_pages);
+
+void drm_agp_chipset_flush(struct drm_device *dev)
+{
+ agp_flush_chipset(dev->agp->bridge);
+}
+EXPORT_SYMBOL(drm_agp_chipset_flush);
+
+#endif /* __OS_HAS_AGP */
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
new file mode 100644
index 00000000000..0e994a0e46d
--- /dev/null
+++ b/drivers/gpu/drm/drm_cache.c
@@ -0,0 +1,69 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+
+#if defined(CONFIG_X86)
+static void
+drm_clflush_page(struct page *page)
+{
+ uint8_t *page_virtual;
+ unsigned int i;
+
+ if (unlikely(page == NULL))
+ return;
+
+ page_virtual = kmap_atomic(page, KM_USER0);
+ for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
+ clflush(page_virtual + i);
+ kunmap_atomic(page_virtual, KM_USER0);
+}
+#endif
+
+void
+drm_clflush_pages(struct page *pages[], unsigned long num_pages)
+{
+
+#if defined(CONFIG_X86)
+ if (cpu_has_clflush) {
+ unsigned long i;
+
+ mb();
+ for (i = 0; i < num_pages; ++i)
+ drm_clflush_page(*pages++);
+ mb();
+
+ return;
+ }
+
+ wbinvd();
+#endif
+}
+EXPORT_SYMBOL(drm_clflush_pages);
diff --git a/drivers/gpu/drm/drm_drawable.c b/drivers/gpu/drm/drm_drawable.c
index 1839c57663c..80be1cab62a 100644
--- a/drivers/gpu/drm/drm_drawable.c
+++ b/drivers/gpu/drm/drm_drawable.c
@@ -76,11 +76,18 @@ int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_draw *draw = data;
unsigned long irqflags;
+ struct drm_drawable_info *info;
spin_lock_irqsave(&dev->drw_lock, irqflags);
- drm_free(drm_get_drawable_info(dev, draw->handle),
- sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
+ info = drm_get_drawable_info(dev, draw->handle);
+ if (info == NULL) {
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ return -EINVAL;
+ }
+ drm_free(info->rects, info->num_rects * sizeof(struct drm_clip_rect),
+ DRM_MEM_BUFS);
+ drm_free(info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
idr_remove(&dev->drw_idr, draw->handle);
@@ -111,7 +118,9 @@ int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file
switch (update->type) {
case DRM_DRAWABLE_CLIPRECTS:
- if (update->num != info->num_rects) {
+ if (update->num == 0)
+ rects = NULL;
+ else if (update->num != info->num_rects) {
rects = drm_alloc(update->num * sizeof(struct drm_clip_rect),
DRM_MEM_BUFS);
} else
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 452c2d866ec..96f416afc3f 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -116,7 +116,13 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
+
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 851a53f1acc..0d46627663b 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -246,7 +246,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
memset(priv, 0, sizeof(*priv));
filp->private_data = priv;
priv->filp = filp;
- priv->uid = current->euid;
+ priv->uid = current_euid();
priv->pid = task_pid_nr(current);
priv->minor = idr_find(&drm_minors_idr, minor_id);
priv->ioctl_count = 0;
@@ -256,6 +256,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
INIT_LIST_HEAD(&priv->lhead);
+ if (dev->driver->driver_features & DRIVER_GEM)
+ drm_gem_open(dev, priv);
+
if (dev->driver->open) {
ret = dev->driver->open(dev, priv);
if (ret < 0)
@@ -400,6 +403,9 @@ int drm_release(struct inode *inode, struct file *filp)
dev->driver->reclaim_buffers(dev, file_priv);
}
+ if (dev->driver->driver_features & DRIVER_GEM)
+ drm_gem_release(dev, file_priv);
+
drm_fasync(-1, filp, 0);
mutex_lock(&dev->ctxlist_mutex);
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
new file mode 100644
index 00000000000..ccd1afdede0
--- /dev/null
+++ b/drivers/gpu/drm/drm_gem.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include "drmP.h"
+
+/** @file drm_gem.c
+ *
+ * This file provides some of the base ioctls and library routines for
+ * the graphics memory manager implemented by each device driver.
+ *
+ * Because various devices have different requirements in terms of
+ * synchronization and migration strategies, implementing that is left up to
+ * the driver, and all that the general API provides should be generic --
+ * allocating objects, reading/writing data with the cpu, freeing objects.
+ * Even there, platform-dependent optimizations for reading/writing data with
+ * the CPU mean we'll likely hook those out to driver-specific calls. However,
+ * the DRI2 implementation wants to have at least allocate/mmap be generic.
+ *
+ * The goal was to have swap-backed object allocation managed through
+ * struct file. However, file descriptors as handles to a struct file have
+ * two major failings:
+ * - Process limits prevent more than 1024 or so being used at a time by
+ * default.
+ * - Inability to allocate high fds will aggravate the X Server's select()
+ * handling, and likely that of many GL client applications as well.
+ *
+ * This led to a plan of using our own integer IDs (called handles, following
+ * DRM terminology) to mimic fds, and implement the fd syscalls we need as
+ * ioctls. The objects themselves will still include the struct file so
+ * that we can transition to fds if the required kernel infrastructure shows
+ * up at a later date, and as our interface with shmfs for memory allocation.
+ */
+
+/**
+ * Initialize the GEM device fields
+ */
+
+int
+drm_gem_init(struct drm_device *dev)
+{
+ spin_lock_init(&dev->object_name_lock);
+ idr_init(&dev->object_name_idr);
+ atomic_set(&dev->object_count, 0);
+ atomic_set(&dev->object_memory, 0);
+ atomic_set(&dev->pin_count, 0);
+ atomic_set(&dev->pin_memory, 0);
+ atomic_set(&dev->gtt_count, 0);
+ atomic_set(&dev->gtt_memory, 0);
+ return 0;
+}
+
+/**
+ * Allocate a GEM object of the specified size with shmfs backing store
+ */
+struct drm_gem_object *
+drm_gem_object_alloc(struct drm_device *dev, size_t size)
+{
+ struct drm_gem_object *obj;
+
+ BUG_ON((size & (PAGE_SIZE - 1)) != 0);
+
+ obj = kcalloc(1, sizeof(*obj), GFP_KERNEL);
+
+ obj->dev = dev;
+ obj->filp = shmem_file_setup("drm mm object", size, 0);
+ if (IS_ERR(obj->filp)) {
+ kfree(obj);
+ return NULL;
+ }
+
+ kref_init(&obj->refcount);
+ kref_init(&obj->handlecount);
+ obj->size = size;
+ if (dev->driver->gem_init_object != NULL &&
+ dev->driver->gem_init_object(obj) != 0) {
+ fput(obj->filp);
+ kfree(obj);
+ return NULL;
+ }
+ atomic_inc(&dev->object_count);
+ atomic_add(obj->size, &dev->object_memory);
+ return obj;
+}
+EXPORT_SYMBOL(drm_gem_object_alloc);
+
+/**
+ * Removes the mapping from handle to filp for this object.
+ */
+static int
+drm_gem_handle_delete(struct drm_file *filp, int handle)
+{
+ struct drm_device *dev;
+ struct drm_gem_object *obj;
+
+ /* This is gross. The idr system doesn't let us try a delete and
+ * return an error code. It just spews if you fail at deleting.
+ * So, we have to grab a lock around finding the object and then
+ * doing the delete on it and dropping the refcount, or the user
+ * could race us to double-decrement the refcount and cause a
+ * use-after-free later. Given the frequency of our handle lookups,
+ * we may want to use ida for number allocation and a hash table
+ * for the pointers, anyway.
+ */
+ spin_lock(&filp->table_lock);
+
+ /* Check if we currently have a reference on the object */
+ obj = idr_find(&filp->object_idr, handle);
+ if (obj == NULL) {
+ spin_unlock(&filp->table_lock);
+ return -EINVAL;
+ }
+ dev = obj->dev;
+
+ /* Release reference and decrement refcount. */
+ idr_remove(&filp->object_idr, handle);
+ spin_unlock(&filp->table_lock);
+
+ mutex_lock(&dev->struct_mutex);
+ drm_gem_object_handle_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+/**
+ * Create a handle for this object. This adds a handle reference
+ * to the object, which includes a regular reference count. Callers
+ * will likely want to dereference the object afterwards.
+ */
+int
+drm_gem_handle_create(struct drm_file *file_priv,
+ struct drm_gem_object *obj,
+ int *handlep)
+{
+ int ret;
+
+ /*
+ * Get the user-visible handle using idr.
+ */
+again:
+ /* ensure there is space available to allocate a handle */
+ if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ /* do the allocation under our spinlock */
+ spin_lock(&file_priv->table_lock);
+ ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep);
+ spin_unlock(&file_priv->table_lock);
+ if (ret == -EAGAIN)
+ goto again;
+
+ if (ret != 0)
+ return ret;
+
+ drm_gem_object_handle_reference(obj);
+ return 0;
+}
+EXPORT_SYMBOL(drm_gem_handle_create);
+
+/** Returns a reference to the object named by the handle. */
+struct drm_gem_object *
+drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
+ int handle)
+{
+ struct drm_gem_object *obj;
+
+ spin_lock(&filp->table_lock);
+
+ /* Check if we currently have a reference on the object */
+ obj = idr_find(&filp->object_idr, handle);
+ if (obj == NULL) {
+ spin_unlock(&filp->table_lock);
+ return NULL;
+ }
+
+ drm_gem_object_reference(obj);
+
+ spin_unlock(&filp->table_lock);
+
+ return obj;
+}
+EXPORT_SYMBOL(drm_gem_object_lookup);
+
+/**
+ * Releases the handle to an mm object.
+ */
+int
+drm_gem_close_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_gem_close *args = data;
+ int ret;
+
+ if (!(dev->driver->driver_features & DRIVER_GEM))
+ return -ENODEV;
+
+ ret = drm_gem_handle_delete(file_priv, args->handle);
+
+ return ret;
+}
+
+/**
+ * Create a global name for an object, returning the name.
+ *
+ * Note that the name does not hold a reference; when the object
+ * is freed, the name goes away.
+ */
+int
+drm_gem_flink_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_gem_flink *args = data;
+ struct drm_gem_object *obj;
+ int ret;
+
+ if (!(dev->driver->driver_features & DRIVER_GEM))
+ return -ENODEV;
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL)
+ return -EBADF;
+
+again:
+ if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ spin_lock(&dev->object_name_lock);
+ if (obj->name) {
+ args->name = obj->name;
+ spin_unlock(&dev->object_name_lock);
+ return 0;
+ }
+ ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
+ &obj->name);
+ spin_unlock(&dev->object_name_lock);
+ if (ret == -EAGAIN)
+ goto again;
+
+ if (ret != 0) {
+ mutex_lock(&dev->struct_mutex);
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+
+ /*
+ * Leave the reference from the lookup around as the
+ * name table now holds one
+ */
+ args->name = (uint64_t) obj->name;
+
+ return 0;
+}
+
+/**
+ * Open an object using the global name, returning a handle and the size.
+ *
+ * This handle (of course) holds a reference to the object, so the object
+ * will not go away until the handle is deleted.
+ */
+int
+drm_gem_open_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_gem_open *args = data;
+ struct drm_gem_object *obj;
+ int ret;
+ int handle;
+
+ if (!(dev->driver->driver_features & DRIVER_GEM))
+ return -ENODEV;
+
+ spin_lock(&dev->object_name_lock);
+ obj = idr_find(&dev->object_name_idr, (int) args->name);
+ if (obj)
+ drm_gem_object_reference(obj);
+ spin_unlock(&dev->object_name_lock);
+ if (!obj)
+ return -ENOENT;
+
+ ret = drm_gem_handle_create(file_priv, obj, &handle);
+ mutex_lock(&dev->struct_mutex);
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ args->handle = handle;
+ args->size = obj->size;
+
+ return 0;
+}
+
+/**
+ * Called at device open time, sets up the structure for handling refcounting
+ * of mm objects.
+ */
+void
+drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
+{
+ idr_init(&file_private->object_idr);
+ spin_lock_init(&file_private->table_lock);
+}
+
+/**
+ * Called at device close to release the file's
+ * handle references on objects.
+ */
+static int
+drm_gem_object_release_handle(int id, void *ptr, void *data)
+{
+ struct drm_gem_object *obj = ptr;
+
+ drm_gem_object_handle_unreference(obj);
+
+ return 0;
+}
+
+/**
+ * Called at close time when the filp is going away.
+ *
+ * Releases any remaining references on objects by this filp.
+ */
+void
+drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
+{
+ mutex_lock(&dev->struct_mutex);
+ idr_for_each(&file_private->object_idr,
+ &drm_gem_object_release_handle, NULL);
+
+ idr_destroy(&file_private->object_idr);
+ mutex_unlock(&dev->struct_mutex);
+}
+
+/**
+ * Called after the last reference to the object has been lost.
+ *
+ * Frees the object
+ */
+void
+drm_gem_object_free(struct kref *kref)
+{
+ struct drm_gem_object *obj = (struct drm_gem_object *) kref;
+ struct drm_device *dev = obj->dev;
+
+ BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+
+ if (dev->driver->gem_free_object != NULL)
+ dev->driver->gem_free_object(obj);
+
+ fput(obj->filp);
+ atomic_dec(&dev->object_count);
+ atomic_sub(obj->size, &dev->object_memory);
+ kfree(obj);
+}
+EXPORT_SYMBOL(drm_gem_object_free);
+
+/**
+ * Called after the last handle to the object has been closed
+ *
+ * Removes any name for the object. Note that this must be
+ * called before drm_gem_object_free or we'll be touching
+ * freed memory
+ */
+void
+drm_gem_object_handle_free(struct kref *kref)
+{
+ struct drm_gem_object *obj = container_of(kref,
+ struct drm_gem_object,
+ handlecount);
+ struct drm_device *dev = obj->dev;
+
+ /* Remove any name for this object */
+ spin_lock(&dev->object_name_lock);
+ if (obj->name) {
+ idr_remove(&dev->object_name_idr, obj->name);
+ spin_unlock(&dev->object_name_lock);
+ /*
+ * The object name held a reference to this object, drop
+ * that now.
+ */
+ drm_gem_object_unreference(obj);
+ } else
+ spin_unlock(&dev->object_name_lock);
+
+}
+EXPORT_SYMBOL(drm_gem_object_handle_free);
+
diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c
index 90f5a8d9bdc..920b72fbc95 100644
--- a/drivers/gpu/drm/drm_ioc32.c
+++ b/drivers/gpu/drm/drm_ioc32.c
@@ -64,6 +64,8 @@
#define DRM_IOCTL_SG_ALLOC32 DRM_IOW( 0x38, drm_scatter_gather32_t)
#define DRM_IOCTL_SG_FREE32 DRM_IOW( 0x39, drm_scatter_gather32_t)
+#define DRM_IOCTL_UPDATE_DRAW32 DRM_IOW( 0x3f, drm_update_draw32_t)
+
#define DRM_IOCTL_WAIT_VBLANK32 DRM_IOWR(0x3a, drm_wait_vblank32_t)
typedef struct drm_version_32 {
@@ -952,6 +954,37 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd,
DRM_IOCTL_SG_FREE, (unsigned long)request);
}
+typedef struct drm_update_draw32 {
+ drm_drawable_t handle;
+ unsigned int type;
+ unsigned int num;
+ /* 64-bit version has a 32-bit pad here */
+ u64 data; /**< Pointer */
+} __attribute__((packed)) drm_update_draw32_t;
+
+static int compat_drm_update_draw(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_update_draw32_t update32;
+ struct drm_update_draw __user *request;
+ int err;
+
+ if (copy_from_user(&update32, (void __user *)arg, sizeof(update32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) ||
+ __put_user(update32.handle, &request->handle) ||
+ __put_user(update32.type, &request->type) ||
+ __put_user(update32.num, &request->num) ||
+ __put_user(update32.data, &request->data))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
+ DRM_IOCTL_UPDATE_DRAW, (unsigned long)request);
+ return err;
+}
+
struct drm_wait_vblank_request32 {
enum drm_vblank_seq_type type;
unsigned int sequence;
@@ -1033,6 +1066,7 @@ drm_ioctl_compat_t *drm_compat_ioctls[] = {
#endif
[DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC32)] = compat_drm_sg_alloc,
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE32)] = compat_drm_sg_free,
+ [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW32)] = compat_drm_update_draw,
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank,
};
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 53f0e5af1cc..212a94f715b 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -63,7 +63,7 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
return -EINVAL;
- p->irq = dev->irq;
+ p->irq = dev->pdev->irq;
DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
p->irq);
@@ -71,25 +71,137 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
return 0;
}
+static void vblank_disable_fn(unsigned long arg)
+{
+ struct drm_device *dev = (struct drm_device *)arg;
+ unsigned long irqflags;
+ int i;
+
+ if (!dev->vblank_disable_allowed)
+ return;
+
+ for (i = 0; i < dev->num_crtcs; i++) {
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
+ dev->vblank_enabled[i]) {
+ DRM_DEBUG("disabling vblank on crtc %d\n", i);
+ dev->last_vblank[i] =
+ dev->driver->get_vblank_counter(dev, i);
+ dev->driver->disable_vblank(dev, i);
+ dev->vblank_enabled[i] = 0;
+ }
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+ }
+}
+
+static void drm_vblank_cleanup(struct drm_device *dev)
+{
+ /* Bail if the driver didn't call drm_vblank_init() */
+ if (dev->num_crtcs == 0)
+ return;
+
+ del_timer(&dev->vblank_disable_timer);
+
+ vblank_disable_fn((unsigned long)dev);
+
+ drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+ drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+ drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+ drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+
+ dev->num_crtcs = 0;
+}
+
+int drm_vblank_init(struct drm_device *dev, int num_crtcs)
+{
+ int i, ret = -ENOMEM;
+
+ setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
+ (unsigned long)dev);
+ spin_lock_init(&dev->vbl_lock);
+ atomic_set(&dev->vbl_signal_pending, 0);
+ dev->num_crtcs = num_crtcs;
+
+ dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->vbl_queue)
+ goto err;
+
+ dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->vbl_sigs)
+ goto err;
+
+ dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->_vblank_count)
+ goto err;
+
+ dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->vblank_refcount)
+ goto err;
+
+ dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int),
+ DRM_MEM_DRIVER);
+ if (!dev->vblank_enabled)
+ goto err;
+
+ dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
+ if (!dev->last_vblank)
+ goto err;
+
+ dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int),
+ DRM_MEM_DRIVER);
+ if (!dev->vblank_inmodeset)
+ goto err;
+
+ /* Zero per-crtc vblank stuff */
+ for (i = 0; i < num_crtcs; i++) {
+ init_waitqueue_head(&dev->vbl_queue[i]);
+ INIT_LIST_HEAD(&dev->vbl_sigs[i]);
+ atomic_set(&dev->_vblank_count[i], 0);
+ atomic_set(&dev->vblank_refcount[i], 0);
+ }
+
+ dev->vblank_disable_allowed = 0;
+
+ return 0;
+
+err:
+ drm_vblank_cleanup(dev);
+ return ret;
+}
+EXPORT_SYMBOL(drm_vblank_init);
+
/**
* Install IRQ handler.
*
* \param dev DRM device.
- * \param irq IRQ number.
*
- * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver
+ * Initializes the IRQ related data. Installs the handler, calling the driver
* \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
* before and after the installation.
*/
-static int drm_irq_install(struct drm_device * dev)
+int drm_irq_install(struct drm_device *dev)
{
- int ret;
+ int ret = 0;
unsigned long sh_flags = 0;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
- if (dev->irq == 0)
+ if (dev->pdev->irq == 0)
return -EINVAL;
mutex_lock(&dev->struct_mutex);
@@ -107,18 +219,7 @@ static int drm_irq_install(struct drm_device * dev)
dev->irq_enabled = 1;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("irq=%d\n", dev->irq);
-
- if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
- init_waitqueue_head(&dev->vbl_queue);
-
- spin_lock_init(&dev->vbl_lock);
-
- INIT_LIST_HEAD(&dev->vbl_sigs);
- INIT_LIST_HEAD(&dev->vbl_sigs2);
-
- dev->vbl_pending = 0;
- }
+ DRM_DEBUG("irq=%d\n", dev->pdev->irq);
/* Before installing handler */
dev->driver->irq_preinstall(dev);
@@ -127,8 +228,9 @@ static int drm_irq_install(struct drm_device * dev)
if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
sh_flags = IRQF_SHARED;
- ret = request_irq(dev->irq, dev->driver->irq_handler,
+ ret = request_irq(drm_dev_to_irq(dev), dev->driver->irq_handler,
sh_flags, dev->devname, dev);
+
if (ret < 0) {
mutex_lock(&dev->struct_mutex);
dev->irq_enabled = 0;
@@ -137,10 +239,16 @@ static int drm_irq_install(struct drm_device * dev)
}
/* After installing handler */
- dev->driver->irq_postinstall(dev);
+ ret = dev->driver->irq_postinstall(dev);
+ if (ret < 0) {
+ mutex_lock(&dev->struct_mutex);
+ dev->irq_enabled = 0;
+ mutex_unlock(&dev->struct_mutex);
+ }
- return 0;
+ return ret;
}
+EXPORT_SYMBOL(drm_irq_install);
/**
* Uninstall the IRQ handler.
@@ -164,17 +272,18 @@ int drm_irq_uninstall(struct drm_device * dev)
if (!irq_enabled)
return -EINVAL;
- DRM_DEBUG("irq=%d\n", dev->irq);
+ DRM_DEBUG("irq=%d\n", dev->pdev->irq);
dev->driver->irq_uninstall(dev);
- free_irq(dev->irq, dev);
+ free_irq(dev->pdev->irq, dev);
+
+ drm_vblank_cleanup(dev);
dev->locked_tasklet_func = NULL;
return 0;
}
-
EXPORT_SYMBOL(drm_irq_uninstall);
/**
@@ -201,7 +310,7 @@ int drm_control(struct drm_device *dev, void *data,
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return 0;
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
- ctl->irq != dev->irq)
+ ctl->irq != dev->pdev->irq)
return -EINVAL;
return drm_irq_install(dev);
case DRM_UNINST_HANDLER:
@@ -214,6 +323,174 @@ int drm_control(struct drm_device *dev, void *data,
}
/**
+ * drm_vblank_count - retrieve "cooked" vblank counter value
+ * @dev: DRM device
+ * @crtc: which counter to retrieve
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity.
+ */
+u32 drm_vblank_count(struct drm_device *dev, int crtc)
+{
+ return atomic_read(&dev->_vblank_count[crtc]);
+}
+EXPORT_SYMBOL(drm_vblank_count);
+
+/**
+ * drm_update_vblank_count - update the master vblank counter
+ * @dev: DRM device
+ * @crtc: counter to update
+ *
+ * Call back into the driver to update the appropriate vblank counter
+ * (specified by @crtc). Deal with wraparound, if it occurred, and
+ * update the last read value so we can deal with wraparound on the next
+ * call if necessary.
+ *
+ * Only necessary when going from off->on, to account for frames we
+ * didn't get an interrupt for.
+ *
+ * Note: caller must hold dev->vbl_lock since this reads & writes
+ * device vblank fields.
+ */
+static void drm_update_vblank_count(struct drm_device *dev, int crtc)
+{
+ u32 cur_vblank, diff;
+
+ /*
+ * Interrupts were disabled prior to this call, so deal with counter
+ * wrap if needed.
+ * NOTE! It's possible we lost a full dev->max_vblank_count events
+ * here if the register is small or we had vblank interrupts off for
+ * a long time.
+ */
+ cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+ diff = cur_vblank - dev->last_vblank[crtc];
+ if (cur_vblank < dev->last_vblank[crtc]) {
+ diff += dev->max_vblank_count;
+
+ DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
+ crtc, dev->last_vblank[crtc], cur_vblank, diff);
+ }
+
+ DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
+ crtc, diff);
+
+ atomic_add(diff, &dev->_vblank_count[crtc]);
+}
+
+/**
+ * drm_vblank_get - get a reference count on vblank events
+ * @dev: DRM device
+ * @crtc: which CRTC to own
+ *
+ * Acquire a reference count on vblank events to avoid having them disabled
+ * while in use.
+ *
+ * RETURNS
+ * Zero on success, nonzero on failure.
+ */
+int drm_vblank_get(struct drm_device *dev, int crtc)
+{
+ unsigned long irqflags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ /* Going from 0->1 means we have to enable interrupts again */
+ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 &&
+ !dev->vblank_enabled[crtc]) {
+ ret = dev->driver->enable_vblank(dev, crtc);
+ DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
+ if (ret)
+ atomic_dec(&dev->vblank_refcount[crtc]);
+ else {
+ dev->vblank_enabled[crtc] = 1;
+ drm_update_vblank_count(dev, crtc);
+ }
+ }
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_vblank_get);
+
+/**
+ * drm_vblank_put - give up ownership of vblank events
+ * @dev: DRM device
+ * @crtc: which counter to give up
+ *
+ * Release ownership of a given vblank counter, turning off interrupts
+ * if possible.
+ */
+void drm_vblank_put(struct drm_device *dev, int crtc)
+{
+ /* Last user schedules interrupt disable */
+ if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
+ mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
+}
+EXPORT_SYMBOL(drm_vblank_put);
+
+/**
+ * drm_modeset_ctl - handle vblank event counter changes across mode switch
+ * @DRM_IOCTL_ARGS: standard ioctl arguments
+ *
+ * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET
+ * ioctls around modesetting so that any lost vblank events are accounted for.
+ *
+ * Generally the counter will reset across mode sets. If interrupts are
+ * enabled around this call, we don't have to do anything since the counter
+ * will have already been incremented.
+ */
+int drm_modeset_ctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_modeset_ctl *modeset = data;
+ unsigned long irqflags;
+ int crtc, ret = 0;
+
+ /* If drm_vblank_init() hasn't been called yet, just no-op */
+ if (!dev->num_crtcs)
+ goto out;
+
+ crtc = modeset->crtc;
+ if (crtc >= dev->num_crtcs) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * To avoid all the problems that might happen if interrupts
+ * were enabled/disabled around or between these calls, we just
+ * have the kernel take a reference on the CRTC (just once though
+ * to avoid corrupting the count if multiple, mismatch calls occur),
+ * so that interrupts remain enabled in the interim.
+ */
+ switch (modeset->cmd) {
+ case _DRM_PRE_MODESET:
+ if (!dev->vblank_inmodeset[crtc]) {
+ dev->vblank_inmodeset[crtc] = 1;
+ drm_vblank_get(dev, crtc);
+ }
+ break;
+ case _DRM_POST_MODESET:
+ if (dev->vblank_inmodeset[crtc]) {
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ dev->vblank_disable_allowed = 1;
+ dev->vblank_inmodeset[crtc] = 0;
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+ drm_vblank_put(dev, crtc);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out:
+ return ret;
+}
+
+/**
* Wait for VBLANK.
*
* \param inode device inode.
@@ -232,14 +509,14 @@ int drm_control(struct drm_device *dev, void *data,
*
* If a signal is not requested, then calls vblank_wait().
*/
-int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int drm_wait_vblank(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
union drm_wait_vblank *vblwait = data;
- struct timeval now;
int ret = 0;
- unsigned int flags, seq;
+ unsigned int flags, seq, crtc;
- if ((!dev->irq) || (!dev->irq_enabled))
+ if ((!dev->pdev->irq) || (!dev->irq_enabled))
return -EINVAL;
if (vblwait->request.type &
@@ -251,13 +528,17 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
}
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
+ crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
- if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
- DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
+ if (crtc >= dev->num_crtcs)
return -EINVAL;
- seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
- : &dev->vbl_received);
+ ret = drm_vblank_get(dev, crtc);
+ if (ret) {
+ DRM_ERROR("failed to acquire vblank counter, %d\n", ret);
+ return ret;
+ }
+ seq = drm_vblank_count(dev, crtc);
switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
case _DRM_VBLANK_RELATIVE:
@@ -266,7 +547,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
case _DRM_VBLANK_ABSOLUTE:
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
if ((flags & _DRM_VBLANK_NEXTONMISS) &&
@@ -276,8 +558,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
if (flags & _DRM_VBLANK_SIGNAL) {
unsigned long irqflags;
- struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
- ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+ struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
struct drm_vbl_sig *vbl_sig;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -298,22 +579,32 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
}
}
- if (dev->vbl_pending >= 100) {
+ if (atomic_read(&dev->vbl_signal_pending) >= 100) {
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
- return -EBUSY;
+ ret = -EBUSY;
+ goto done;
}
- dev->vbl_pending++;
-
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
- if (!
- (vbl_sig =
- drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) {
- return -ENOMEM;
+ vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig),
+ DRM_MEM_DRIVER);
+ if (!vbl_sig) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Get a refcount on the vblank, which will be released by
+ * drm_vbl_send_signals().
+ */
+ ret = drm_vblank_get(dev, crtc);
+ if (ret) {
+ drm_free(vbl_sig, sizeof(struct drm_vbl_sig),
+ DRM_MEM_DRIVER);
+ goto done;
}
- memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
+ atomic_inc(&dev->vbl_signal_pending);
vbl_sig->sequence = vblwait->request.sequence;
vbl_sig->info.si_signo = vblwait->request.signal;
@@ -327,20 +618,29 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
vblwait->reply.sequence = seq;
} else {
- if (flags & _DRM_VBLANK_SECONDARY) {
- if (dev->driver->vblank_wait2)
- ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence);
- } else if (dev->driver->vblank_wait)
- ret =
- dev->driver->vblank_wait(dev,
- &vblwait->request.sequence);
-
- do_gettimeofday(&now);
- vblwait->reply.tval_sec = now.tv_sec;
- vblwait->reply.tval_usec = now.tv_usec;
+ DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
+ vblwait->request.sequence, crtc);
+ DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
+ ((drm_vblank_count(dev, crtc)
+ - vblwait->request.sequence) <= (1 << 23)));
+
+ if (ret != -EINTR) {
+ struct timeval now;
+
+ do_gettimeofday(&now);
+
+ vblwait->reply.tval_sec = now.tv_sec;
+ vblwait->reply.tval_usec = now.tv_usec;
+ vblwait->reply.sequence = drm_vblank_count(dev, crtc);
+ DRM_DEBUG("returning %d to client\n",
+ vblwait->reply.sequence);
+ } else {
+ DRM_DEBUG("vblank wait interrupted by signal\n");
+ }
}
- done:
+done:
+ drm_vblank_put(dev, crtc);
return ret;
}
@@ -348,44 +648,57 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
* Send the VBLANK signals.
*
* \param dev DRM device.
+ * \param crtc CRTC where the vblank event occurred
*
* Sends a signal for each task in drm_device::vbl_sigs and empties the list.
*
* If a signal is not requested, then calls vblank_wait().
*/
-void drm_vbl_send_signals(struct drm_device * dev)
+static void drm_vbl_send_signals(struct drm_device *dev, int crtc)
{
+ struct drm_vbl_sig *vbl_sig, *tmp;
+ struct list_head *vbl_sigs;
+ unsigned int vbl_seq;
unsigned long flags;
- int i;
spin_lock_irqsave(&dev->vbl_lock, flags);
- for (i = 0; i < 2; i++) {
- struct drm_vbl_sig *vbl_sig, *tmp;
- struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
- unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
- &dev->vbl_received);
+ vbl_sigs = &dev->vbl_sigs[crtc];
+ vbl_seq = drm_vblank_count(dev, crtc);
- list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
- if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
- vbl_sig->info.si_code = vbl_seq;
- send_sig_info(vbl_sig->info.si_signo,
- &vbl_sig->info, vbl_sig->task);
+ list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
+ if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
+ vbl_sig->info.si_code = vbl_seq;
+ send_sig_info(vbl_sig->info.si_signo,
+ &vbl_sig->info, vbl_sig->task);
- list_del(&vbl_sig->head);
-
- drm_free(vbl_sig, sizeof(*vbl_sig),
- DRM_MEM_DRIVER);
+ list_del(&vbl_sig->head);
- dev->vbl_pending--;
- }
- }
+ drm_free(vbl_sig, sizeof(*vbl_sig),
+ DRM_MEM_DRIVER);
+ atomic_dec(&dev->vbl_signal_pending);
+ drm_vblank_put(dev, crtc);
+ }
}
spin_unlock_irqrestore(&dev->vbl_lock, flags);
}
-EXPORT_SYMBOL(drm_vbl_send_signals);
+/**
+ * drm_handle_vblank - handle a vblank event
+ * @dev: DRM device
+ * @crtc: where this event occurred
+ *
+ * Drivers should call this routine in their vblank interrupt handlers to
+ * update the vblank counter and send any signals that may be pending.
+ */
+void drm_handle_vblank(struct drm_device *dev, int crtc)
+{
+ atomic_inc(&dev->_vblank_count[crtc]);
+ DRM_WAKEUP(&dev->vbl_queue[crtc]);
+ drm_vbl_send_signals(dev, crtc);
+}
+EXPORT_SYMBOL(drm_handle_vblank);
/**
* Tasklet wrapper function.
diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c
index a4caf95485d..888159e03d2 100644
--- a/drivers/gpu/drm/drm_lock.c
+++ b/drivers/gpu/drm/drm_lock.c
@@ -232,6 +232,7 @@ int drm_lock_take(struct drm_lock_data *lock_data,
}
return 0;
}
+EXPORT_SYMBOL(drm_lock_take);
/**
* This takes a lock forcibly and hands it to context. Should ONLY be used
@@ -299,6 +300,7 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
wake_up_interruptible(&lock_data->lock_queue);
return 0;
}
+EXPORT_SYMBOL(drm_lock_free);
/**
* If we get here, it means that the process has called DRM_IOCTL_LOCK
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
index 0177012845c..803bc9e7ce3 100644
--- a/drivers/gpu/drm/drm_memory.c
+++ b/drivers/gpu/drm/drm_memory.c
@@ -133,6 +133,7 @@ int drm_free_agp(DRM_AGP_MEM * handle, int pages)
{
return drm_agp_free_memory(handle) ? 0 : -EINVAL;
}
+EXPORT_SYMBOL(drm_free_agp);
/** Wrapper around agp_bind_memory() */
int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
@@ -145,6 +146,7 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
{
return drm_agp_unbind_memory(handle);
}
+EXPORT_SYMBOL(drm_unbind_agp);
#else /* __OS_HAS_AGP */
static inline void *agp_remap(unsigned long offset, unsigned long size,
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index dcff9e9b52e..217ad7dc707 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -169,6 +169,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
return child;
}
+EXPORT_SYMBOL(drm_mm_get_block);
/*
* Put a block. Merge with the previous and / or next block if they are free.
@@ -217,6 +218,7 @@ void drm_mm_put_block(struct drm_mm_node * cur)
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
}
}
+EXPORT_SYMBOL(drm_mm_put_block);
struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
unsigned long size,
@@ -265,6 +267,7 @@ int drm_mm_clean(struct drm_mm * mm)
return (head->next->next == head);
}
+EXPORT_SYMBOL(drm_mm_search_free);
int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
{
@@ -273,7 +276,7 @@ int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
return drm_mm_create_tail_node(mm, start, size);
}
-
+EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(struct drm_mm * mm)
{
diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c
index 93b1e0475c9..ae73b7f7249 100644
--- a/drivers/gpu/drm/drm_proc.c
+++ b/drivers/gpu/drm/drm_proc.c
@@ -49,6 +49,10 @@ static int drm_queues_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
static int drm_bufs_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
+static int drm_gem_name_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+static int drm_gem_object_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
#if DRM_DEBUG_CODE
static int drm_vma_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
@@ -60,13 +64,16 @@ static int drm_vma_info(char *buf, char **start, off_t offset,
static struct drm_proc_list {
const char *name; /**< file name */
int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/
+ u32 driver_features; /**< Required driver features for this entry */
} drm_proc_list[] = {
- {"name", drm_name_info},
- {"mem", drm_mem_info},
- {"vm", drm_vm_info},
- {"clients", drm_clients_info},
- {"queues", drm_queues_info},
- {"bufs", drm_bufs_info},
+ {"name", drm_name_info, 0},
+ {"mem", drm_mem_info, 0},
+ {"vm", drm_vm_info, 0},
+ {"clients", drm_clients_info, 0},
+ {"queues", drm_queues_info, 0},
+ {"bufs", drm_bufs_info, 0},
+ {"gem_names", drm_gem_name_info, DRIVER_GEM},
+ {"gem_objects", drm_gem_object_info, DRIVER_GEM},
#if DRM_DEBUG_CODE
{"vma", drm_vma_info},
#endif
@@ -90,8 +97,9 @@ static struct drm_proc_list {
int drm_proc_init(struct drm_minor *minor, int minor_id,
struct proc_dir_entry *root)
{
+ struct drm_device *dev = minor->dev;
struct proc_dir_entry *ent;
- int i, j;
+ int i, j, ret;
char name[64];
sprintf(name, "%d", minor_id);
@@ -102,23 +110,42 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
}
for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+ u32 features = drm_proc_list[i].driver_features;
+
+ if (features != 0 &&
+ (dev->driver->driver_features & features) != features)
+ continue;
+
ent = create_proc_entry(drm_proc_list[i].name,
S_IFREG | S_IRUGO, minor->dev_root);
if (!ent) {
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
name, drm_proc_list[i].name);
- for (j = 0; j < i; j++)
- remove_proc_entry(drm_proc_list[i].name,
- minor->dev_root);
- remove_proc_entry(name, root);
- minor->dev_root = NULL;
- return -1;
+ ret = -1;
+ goto fail;
}
ent->read_proc = drm_proc_list[i].f;
ent->data = minor;
}
+ if (dev->driver->proc_init) {
+ ret = dev->driver->proc_init(minor);
+ if (ret) {
+ DRM_ERROR("DRM: Driver failed to initialize "
+ "/proc/dri.\n");
+ goto fail;
+ }
+ }
+
return 0;
+ fail:
+
+ for (j = 0; j < i; j++)
+ remove_proc_entry(drm_proc_list[i].name,
+ minor->dev_root);
+ remove_proc_entry(name, root);
+ minor->dev_root = NULL;
+ return ret;
}
/**
@@ -133,12 +160,16 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
*/
int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
{
+ struct drm_device *dev = minor->dev;
int i;
char name[64];
if (!root || !minor->dev_root)
return 0;
+ if (dev->driver->proc_cleanup)
+ dev->driver->proc_cleanup(minor);
+
for (i = 0; i < DRM_PROC_ENTRIES; i++)
remove_proc_entry(drm_proc_list[i].name, minor->dev_root);
sprintf(name, "%d", minor->index);
@@ -480,6 +511,84 @@ static int drm_clients_info(char *buf, char **start, off_t offset,
return ret;
}
+struct drm_gem_name_info_data {
+ int len;
+ char *buf;
+ int eof;
+};
+
+static int drm_gem_one_name_info(int id, void *ptr, void *data)
+{
+ struct drm_gem_object *obj = ptr;
+ struct drm_gem_name_info_data *nid = data;
+
+ DRM_INFO("name %d size %zd\n", obj->name, obj->size);
+ if (nid->eof)
+ return 0;
+
+ nid->len += sprintf(&nid->buf[nid->len],
+ "%6d %8zd %7d %8d\n",
+ obj->name, obj->size,
+ atomic_read(&obj->handlecount.refcount),
+ atomic_read(&obj->refcount.refcount));
+ if (nid->len > DRM_PROC_LIMIT) {
+ nid->eof = 1;
+ return 0;
+ }
+ return 0;
+}
+
+static int drm_gem_name_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ struct drm_gem_name_info_data nid;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ nid.len = sprintf(buf, " name size handles refcount\n");
+ nid.buf = buf;
+ nid.eof = 0;
+ idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, &nid);
+
+ *start = &buf[offset];
+ *eof = 0;
+ if (nid.len > request + offset)
+ return request;
+ *eof = 1;
+ return nid.len - offset;
+}
+
+static int drm_gem_object_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+ DRM_PROC_PRINT("%d objects\n", atomic_read(&dev->object_count));
+ DRM_PROC_PRINT("%d object bytes\n", atomic_read(&dev->object_memory));
+ DRM_PROC_PRINT("%d pinned\n", atomic_read(&dev->pin_count));
+ DRM_PROC_PRINT("%d pin bytes\n", atomic_read(&dev->pin_memory));
+ DRM_PROC_PRINT("%d gtt bytes\n", atomic_read(&dev->gtt_memory));
+ DRM_PROC_PRINT("%d gtt total\n", dev->gtt_total);
+ if (len > request + offset)
+ return request;
+ *eof = 1;
+ return len - offset;
+}
+
#if DRM_DEBUG_CODE
static int drm__vma_info(char *buf, char **start, off_t offset, int request,
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index c2f584f3b46..141e33004a7 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -107,7 +107,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
#ifdef __alpha__
dev->hose = pdev->sysdata;
#endif
- dev->irq = pdev->irq;
if (drm_ht_create(&dev->map_hash, 12)) {
return -ENOMEM;
@@ -152,6 +151,15 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
goto error_out_unreg;
}
+ if (driver->driver_features & DRIVER_GEM) {
+ retcode = drm_gem_init(dev);
+ if (retcode) {
+ DRM_ERROR("Cannot initialize graphics execution "
+ "manager (GEM)\n");
+ goto error_out_unreg;
+ }
+ }
+
return 0;
error_out_unreg:
@@ -317,6 +325,7 @@ int drm_put_dev(struct drm_device * dev)
int drm_put_minor(struct drm_minor **minor_p)
{
struct drm_minor *minor = *minor_p;
+
DRM_DEBUG("release secondary minor %d\n", minor->index);
if (minor->type == DRM_MINOR_LEGACY)
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index af211a0ef17..1611b9bcbe7 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -184,7 +184,7 @@ int drm_sysfs_device_add(struct drm_minor *minor)
err_out_files:
if (i > 0)
for (j = 0; j < i; j++)
- device_remove_file(&minor->kdev, &device_attrs[i]);
+ device_remove_file(&minor->kdev, &device_attrs[j]);
device_unregister(&minor->kdev);
err_out:
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index a9e60464df7..5ba78e4fd2b 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -3,7 +3,12 @@
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ccflags-y := -Iinclude/drm
-i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
+i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_opregion.o \
+ i915_suspend.o \
+ i915_gem.o \
+ i915_gem_debug.o \
+ i915_gem_proc.o \
+ i915_gem_tiling.o
i915-$(CONFIG_COMPAT) += i915_ioc32.o
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9ac4720e647..01de536e021 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -40,40 +40,96 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
- u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+ u32 last_acthd = I915_READ(acthd_reg);
+ u32 acthd;
+ u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
int i;
- for (i = 0; i < 10000; i++) {
- ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ for (i = 0; i < 100000; i++) {
+ ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ acthd = I915_READ(acthd_reg);
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
if (ring->space >= n)
return 0;
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
if (ring->head != last_head)
i = 0;
+ if (acthd != last_acthd)
+ i = 0;
last_head = ring->head;
+ last_acthd = acthd;
+ msleep_interruptible(10);
+
}
return -EBUSY;
}
+/**
+ * Sets up the hardware status page for devices that need a physical address
+ * in the register.
+ */
+static int i915_init_phys_hws(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ /* Program Hardware Status Page */
+ dev_priv->status_page_dmah =
+ drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
+
+ if (!dev_priv->status_page_dmah) {
+ DRM_ERROR("Can not allocate hardware status page\n");
+ return -ENOMEM;
+ }
+ dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
+ dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
+
+ memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+
+ I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
+ DRM_DEBUG("Enabled hardware status page\n");
+ return 0;
+}
+
+/**
+ * Frees the hardware status page, whether it's a physical address or a virtual
+ * address set up by the X Server.
+ */
+static void i915_free_hws(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ if (dev_priv->status_page_dmah) {
+ drm_pci_free(dev, dev_priv->status_page_dmah);
+ dev_priv->status_page_dmah = NULL;
+ }
+
+ if (dev_priv->status_gfx_addr) {
+ dev_priv->status_gfx_addr = 0;
+ drm_core_ioremapfree(&dev_priv->hws_map, dev);
+ }
+
+ /* Need to rewrite hardware status page */
+ I915_WRITE(HWS_PGA, 0x1ffff000);
+}
+
void i915_kernel_lost_context(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
- ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
- ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
+ ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
- if (ring->head == ring->tail)
+ if (ring->head == ring->tail && dev_priv->sarea_priv)
dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
}
@@ -84,28 +140,19 @@ static int i915_dma_cleanup(struct drm_device * dev)
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if (dev->irq)
+ if (dev->irq_enabled)
drm_irq_uninstall(dev);
if (dev_priv->ring.virtual_start) {
drm_core_ioremapfree(&dev_priv->ring.map, dev);
- dev_priv->ring.virtual_start = 0;
- dev_priv->ring.map.handle = 0;
+ dev_priv->ring.virtual_start = NULL;
+ dev_priv->ring.map.handle = NULL;
dev_priv->ring.map.size = 0;
}
- if (dev_priv->status_page_dmah) {
- drm_pci_free(dev, dev_priv->status_page_dmah);
- dev_priv->status_page_dmah = NULL;
- /* Need to rewrite hardware status page */
- I915_WRITE(0x02080, 0x1ffff000);
- }
-
- if (dev_priv->status_gfx_addr) {
- dev_priv->status_gfx_addr = 0;
- drm_core_ioremapfree(&dev_priv->hws_map, dev);
- I915_WRITE(0x2080, 0x1ffff000);
- }
+ /* Clear the HWS virtual address at teardown */
+ if (I915_NEED_GFX_HWS(dev))
+ i915_free_hws(dev);
return 0;
}
@@ -121,34 +168,34 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
return -EINVAL;
}
- dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
- if (!dev_priv->mmio_map) {
- i915_dma_cleanup(dev);
- DRM_ERROR("can not find mmio map!\n");
- return -EINVAL;
- }
-
dev_priv->sarea_priv = (drm_i915_sarea_t *)
((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
- dev_priv->ring.Start = init->ring_start;
- dev_priv->ring.End = init->ring_end;
- dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+ if (init->ring_size != 0) {
+ if (dev_priv->ring.ring_obj != NULL) {
+ i915_dma_cleanup(dev);
+ DRM_ERROR("Client tried to initialize ringbuffer in "
+ "GEM mode\n");
+ return -EINVAL;
+ }
- dev_priv->ring.map.offset = init->ring_start;
- dev_priv->ring.map.size = init->ring_size;
- dev_priv->ring.map.type = 0;
- dev_priv->ring.map.flags = 0;
- dev_priv->ring.map.mtrr = 0;
+ dev_priv->ring.Size = init->ring_size;
+ dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
- drm_core_ioremap(&dev_priv->ring.map, dev);
+ dev_priv->ring.map.offset = init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = 0;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
- if (dev_priv->ring.map.handle == NULL) {
- i915_dma_cleanup(dev);
- DRM_ERROR("can not ioremap virtual address for"
- " ring buffer\n");
- return -ENOMEM;
+ drm_core_ioremap(&dev_priv->ring.map, dev);
+
+ if (dev_priv->ring.map.handle == NULL) {
+ i915_dma_cleanup(dev);
+ DRM_ERROR("can not ioremap virtual address for"
+ " ring buffer\n");
+ return -ENOMEM;
+ }
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -159,34 +206,10 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
dev_priv->current_page = 0;
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
- /* We are using separate values as placeholders for mechanisms for
- * private backbuffer/depthbuffer usage.
- */
- dev_priv->use_mi_batchbuffer_start = 0;
- if (IS_I965G(dev)) /* 965 doesn't support older method */
- dev_priv->use_mi_batchbuffer_start = 1;
-
/* Allow hardware batchbuffers unless told otherwise.
*/
dev_priv->allow_batchbuffer = 1;
- /* Program Hardware Status Page */
- if (!I915_NEED_GFX_HWS(dev)) {
- dev_priv->status_page_dmah =
- drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
-
- if (!dev_priv->status_page_dmah) {
- i915_dma_cleanup(dev);
- DRM_ERROR("Can not allocate hardware status page\n");
- return -ENOMEM;
- }
- dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
- dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
-
- memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
- I915_WRITE(0x02080, dev_priv->dma_status_page);
- }
- DRM_DEBUG("Enabled hardware status page\n");
return 0;
}
@@ -201,11 +224,6 @@ static int i915_dma_resume(struct drm_device * dev)
return -EINVAL;
}
- if (!dev_priv->mmio_map) {
- DRM_ERROR("can not find mmio map!\n");
- return -EINVAL;
- }
-
if (dev_priv->ring.map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
@@ -220,9 +238,9 @@ static int i915_dma_resume(struct drm_device * dev)
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
if (dev_priv->status_gfx_addr != 0)
- I915_WRITE(0x02080, dev_priv->status_gfx_addr);
+ I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
else
- I915_WRITE(0x02080, dev_priv->dma_status_page);
+ I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
return 0;
@@ -367,9 +385,10 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
return 0;
}
-static int i915_emit_box(struct drm_device * dev,
- struct drm_clip_rect __user * boxes,
- int i, int DR1, int DR4)
+int
+i915_emit_box(struct drm_device *dev,
+ struct drm_clip_rect __user *boxes,
+ int i, int DR1, int DR4)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_clip_rect box;
@@ -415,14 +434,15 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
-
+ dev_priv->counter++;
if (dev_priv->counter > 0x7FFFFFFFUL)
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
+ dev_priv->counter = 0;
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
BEGIN_LP_RING(4);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(20);
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
OUT_RING(dev_priv->counter);
OUT_RING(0);
ADVANCE_LP_RING();
@@ -486,7 +506,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
return ret;
}
- if (dev_priv->use_mi_batchbuffer_start) {
+ if (!IS_I830(dev) && !IS_845G(dev)) {
BEGIN_LP_RING(2);
if (IS_I965G(dev)) {
OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
@@ -516,6 +536,9 @@ static int i915_dispatch_flip(struct drm_device * dev)
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
+ if (!dev_priv->sarea_priv)
+ return -EINVAL;
+
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
__func__,
dev_priv->current_page,
@@ -524,7 +547,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
i915_kernel_lost_context(dev);
BEGIN_LP_RING(2);
- OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
+ OUT_RING(MI_FLUSH | MI_READ_FLUSH);
OUT_RING(0);
ADVANCE_LP_RING();
@@ -549,8 +572,8 @@ static int i915_dispatch_flip(struct drm_device * dev)
dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
BEGIN_LP_RING(4);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(20);
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
OUT_RING(dev_priv->counter);
OUT_RING(0);
ADVANCE_LP_RING();
@@ -570,9 +593,15 @@ static int i915_quiescent(struct drm_device * dev)
static int i915_flush_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- LOCK_TEST_WITH_RETURN(dev, file_priv);
+ int ret;
+
+ RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+ mutex_lock(&dev->struct_mutex);
+ ret = i915_quiescent(dev);
+ mutex_unlock(&dev->struct_mutex);
- return i915_quiescent(dev);
+ return ret;
}
static int i915_batchbuffer(struct drm_device *dev, void *data,
@@ -593,16 +622,19 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
batch->start, batch->used, batch->num_cliprects);
- LOCK_TEST_WITH_RETURN(dev, file_priv);
+ RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
batch->num_cliprects *
sizeof(struct drm_clip_rect)))
return -EFAULT;
+ mutex_lock(&dev->struct_mutex);
ret = i915_dispatch_batchbuffer(dev, batch);
+ mutex_unlock(&dev->struct_mutex);
- sarea_priv->last_dispatch = (int)hw_status[5];
+ if (sarea_priv)
+ sarea_priv->last_dispatch = (int)hw_status[5];
return ret;
}
@@ -619,7 +651,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
- LOCK_TEST_WITH_RETURN(dev, file_priv);
+ RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
if (cmdbuf->num_cliprects &&
DRM_VERIFYAREA_READ(cmdbuf->cliprects,
@@ -629,24 +661,33 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
return -EFAULT;
}
+ mutex_lock(&dev->struct_mutex);
ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
+ mutex_unlock(&dev->struct_mutex);
if (ret) {
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
return ret;
}
- sarea_priv->last_dispatch = (int)hw_status[5];
+ if (sarea_priv)
+ sarea_priv->last_dispatch = (int)hw_status[5];
return 0;
}
static int i915_flip_bufs(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
+ int ret;
+
DRM_DEBUG("%s\n", __func__);
- LOCK_TEST_WITH_RETURN(dev, file_priv);
+ RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+ mutex_lock(&dev->struct_mutex);
+ ret = i915_dispatch_flip(dev);
+ mutex_unlock(&dev->struct_mutex);
- return i915_dispatch_flip(dev);
+ return ret;
}
static int i915_getparam(struct drm_device *dev, void *data,
@@ -663,7 +704,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
switch (param->param) {
case I915_PARAM_IRQ_ACTIVE:
- value = dev->irq ? 1 : 0;
+ value = dev->pdev->irq ? 1 : 0;
break;
case I915_PARAM_ALLOW_BATCHBUFFER:
value = dev_priv->allow_batchbuffer ? 1 : 0;
@@ -671,6 +712,12 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_LAST_DISPATCH:
value = READ_BREADCRUMB(dev_priv);
break;
+ case I915_PARAM_CHIPSET_ID:
+ value = dev->pci_device;
+ break;
+ case I915_PARAM_HAS_GEM:
+ value = 1;
+ break;
default:
DRM_ERROR("Unknown parameter %d\n", param->param);
return -EINVAL;
@@ -697,8 +744,6 @@ static int i915_setparam(struct drm_device *dev, void *data,
switch (param->param) {
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
- if (!IS_I965G(dev))
- dev_priv->use_mi_batchbuffer_start = param->value;
break;
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
dev_priv->tex_lru_log_granularity = param->value;
@@ -749,8 +794,8 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
dev_priv->hw_status_page = dev_priv->hws_map.handle;
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
- I915_WRITE(0x02080, dev_priv->status_gfx_addr);
- DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",
+ I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
+ DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
dev_priv->status_gfx_addr);
DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
return 0;
@@ -776,14 +821,41 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
memset(dev_priv, 0, sizeof(drm_i915_private_t));
dev->dev_private = (void *)dev_priv;
+ dev_priv->dev = dev;
/* Add register map (needed for suspend/resume) */
base = drm_get_resource_start(dev, mmio_bar);
size = drm_get_resource_len(dev, mmio_bar);
- ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
- _DRM_KERNEL | _DRM_DRIVER,
- &dev_priv->mmio_map);
+ dev_priv->regs = ioremap(base, size);
+
+ i915_gem_load(dev);
+
+ /* Init HWS */
+ if (!I915_NEED_GFX_HWS(dev)) {
+ ret = i915_init_phys_hws(dev);
+ if (ret != 0)
+ return ret;
+ }
+
+ /* On the 945G/GM, the chipset reports the MSI capability on the
+ * integrated graphics even though the support isn't actually there
+ * according to the published specs. It doesn't appear to function
+ * correctly in testing on 945G.
+ * This may be a side effect of MSI having been made available for PEG
+ * and the registers being closely associated.
+ *
+ * According to chipset errata, on the 965GM, MSI interrupts may
+ * be lost or delayed
+ */
+ if (!IS_I945G(dev) && !IS_I945GM(dev) && !IS_I965GM(dev))
+ if (pci_enable_msi(dev->pdev))
+ DRM_ERROR("failed to enable MSI\n");
+
+ intel_opregion_init(dev);
+
+ spin_lock_init(&dev_priv->user_irq_lock);
+
return ret;
}
@@ -791,8 +863,15 @@ int i915_driver_unload(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (dev_priv->mmio_map)
- drm_rmmap(dev, dev_priv->mmio_map);
+ if (dev->pdev->msi_enabled)
+ pci_disable_msi(dev->pdev);
+
+ i915_free_hws(dev);
+
+ if (dev_priv->regs != NULL)
+ iounmap(dev_priv->regs);
+
+ intel_opregion_free(dev);
drm_free(dev->dev_private, sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
@@ -800,6 +879,25 @@ int i915_driver_unload(struct drm_device *dev)
return 0;
}
+int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+{
+ struct drm_i915_file_private *i915_file_priv;
+
+ DRM_DEBUG("\n");
+ i915_file_priv = (struct drm_i915_file_private *)
+ drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES);
+
+ if (!i915_file_priv)
+ return -ENOMEM;
+
+ file_priv->driver_priv = i915_file_priv;
+
+ i915_file_priv->mm.last_gem_seqno = 0;
+ i915_file_priv->mm.last_gem_throttle_seqno = 0;
+
+ return 0;
+}
+
void i915_driver_lastclose(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -807,6 +905,8 @@ void i915_driver_lastclose(struct drm_device * dev)
if (!dev_priv)
return;
+ i915_gem_lastclose(dev);
+
if (dev_priv->agp_heap)
i915_mem_takedown(&(dev_priv->agp_heap));
@@ -819,6 +919,13 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
i915_mem_release(dev, file_priv, dev_priv->agp_heap);
}
+void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
+{
+ struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+
+ drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES);
+}
+
struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
@@ -836,7 +943,23 @@ struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ),
DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0),
+ DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0),
+ DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0),
+ DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0),
+ DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0),
+ DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0),
+ DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0),
+ DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0),
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 93aed1c38bd..a80ead21528 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -38,211 +38,9 @@ static struct pci_device_id pciidlist[] = {
i915_PCI_IDS
};
-enum pipe {
- PIPE_A = 0,
- PIPE_B,
-};
-
-static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (pipe == PIPE_A)
- return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE);
- else
- return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE);
-}
-
-static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
- u32 *array;
- int i;
-
- if (!i915_pipe_enabled(dev, pipe))
- return;
-
- if (pipe == PIPE_A)
- array = dev_priv->save_palette_a;
- else
- array = dev_priv->save_palette_b;
-
- for(i = 0; i < 256; i++)
- array[i] = I915_READ(reg + (i << 2));
-}
-
-static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
- u32 *array;
- int i;
-
- if (!i915_pipe_enabled(dev, pipe))
- return;
-
- if (pipe == PIPE_A)
- array = dev_priv->save_palette_a;
- else
- array = dev_priv->save_palette_b;
-
- for(i = 0; i < 256; i++)
- I915_WRITE(reg + (i << 2), array[i]);
-}
-
-static u8 i915_read_indexed(u16 index_port, u16 data_port, u8 reg)
-{
- outb(reg, index_port);
- return inb(data_port);
-}
-
-static u8 i915_read_ar(u16 st01, u8 reg, u16 palette_enable)
-{
- inb(st01);
- outb(palette_enable | reg, VGA_AR_INDEX);
- return inb(VGA_AR_DATA_READ);
-}
-
-static void i915_write_ar(u8 st01, u8 reg, u8 val, u16 palette_enable)
-{
- inb(st01);
- outb(palette_enable | reg, VGA_AR_INDEX);
- outb(val, VGA_AR_DATA_WRITE);
-}
-
-static void i915_write_indexed(u16 index_port, u16 data_port, u8 reg, u8 val)
-{
- outb(reg, index_port);
- outb(val, data_port);
-}
-
-static void i915_save_vga(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int i;
- u16 cr_index, cr_data, st01;
-
- /* VGA color palette registers */
- dev_priv->saveDACMASK = inb(VGA_DACMASK);
- /* DACCRX automatically increments during read */
- outb(0, VGA_DACRX);
- /* Read 3 bytes of color data from each index */
- for (i = 0; i < 256 * 3; i++)
- dev_priv->saveDACDATA[i] = inb(VGA_DACDATA);
-
- /* MSR bits */
- dev_priv->saveMSR = inb(VGA_MSR_READ);
- if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
- cr_index = VGA_CR_INDEX_CGA;
- cr_data = VGA_CR_DATA_CGA;
- st01 = VGA_ST01_CGA;
- } else {
- cr_index = VGA_CR_INDEX_MDA;
- cr_data = VGA_CR_DATA_MDA;
- st01 = VGA_ST01_MDA;
- }
-
- /* CRT controller regs */
- i915_write_indexed(cr_index, cr_data, 0x11,
- i915_read_indexed(cr_index, cr_data, 0x11) &
- (~0x80));
- for (i = 0; i <= 0x24; i++)
- dev_priv->saveCR[i] =
- i915_read_indexed(cr_index, cr_data, i);
- /* Make sure we don't turn off CR group 0 writes */
- dev_priv->saveCR[0x11] &= ~0x80;
-
- /* Attribute controller registers */
- inb(st01);
- dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX);
- for (i = 0; i <= 0x14; i++)
- dev_priv->saveAR[i] = i915_read_ar(st01, i, 0);
- inb(st01);
- outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX);
- inb(st01);
-
- /* Graphics controller registers */
- for (i = 0; i < 9; i++)
- dev_priv->saveGR[i] =
- i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, i);
-
- dev_priv->saveGR[0x10] =
- i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10);
- dev_priv->saveGR[0x11] =
- i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11);
- dev_priv->saveGR[0x18] =
- i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18);
-
- /* Sequencer registers */
- for (i = 0; i < 8; i++)
- dev_priv->saveSR[i] =
- i915_read_indexed(VGA_SR_INDEX, VGA_SR_DATA, i);
-}
-
-static void i915_restore_vga(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int i;
- u16 cr_index, cr_data, st01;
-
- /* MSR bits */
- outb(dev_priv->saveMSR, VGA_MSR_WRITE);
- if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
- cr_index = VGA_CR_INDEX_CGA;
- cr_data = VGA_CR_DATA_CGA;
- st01 = VGA_ST01_CGA;
- } else {
- cr_index = VGA_CR_INDEX_MDA;
- cr_data = VGA_CR_DATA_MDA;
- st01 = VGA_ST01_MDA;
- }
-
- /* Sequencer registers, don't write SR07 */
- for (i = 0; i < 7; i++)
- i915_write_indexed(VGA_SR_INDEX, VGA_SR_DATA, i,
- dev_priv->saveSR[i]);
-
- /* CRT controller regs */
- /* Enable CR group 0 writes */
- i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]);
- for (i = 0; i <= 0x24; i++)
- i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]);
-
- /* Graphics controller regs */
- for (i = 0; i < 9; i++)
- i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, i,
- dev_priv->saveGR[i]);
-
- i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10,
- dev_priv->saveGR[0x10]);
- i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11,
- dev_priv->saveGR[0x11]);
- i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18,
- dev_priv->saveGR[0x18]);
-
- /* Attribute controller registers */
- inb(st01);
- for (i = 0; i <= 0x14; i++)
- i915_write_ar(st01, i, dev_priv->saveAR[i], 0);
- inb(st01); /* switch back to index mode */
- outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX);
- inb(st01);
-
- /* VGA color palette registers */
- outb(dev_priv->saveDACMASK, VGA_DACMASK);
- /* DACCRX automatically increments during read */
- outb(0, VGA_DACWX);
- /* Read 3 bytes of color data from each index */
- for (i = 0; i < 256 * 3; i++)
- outb(dev_priv->saveDACDATA[i], VGA_DACDATA);
-
-}
-
static int i915_suspend(struct drm_device *dev, pm_message_t state)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int i;
if (!dev || !dev_priv) {
printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv);
@@ -254,122 +52,10 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
return 0;
pci_save_state(dev->pdev);
- pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
-
- /* Display arbitration control */
- dev_priv->saveDSPARB = I915_READ(DSPARB);
-
- /* Pipe & plane A info */
- dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
- dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
- dev_priv->saveFPA0 = I915_READ(FPA0);
- dev_priv->saveFPA1 = I915_READ(FPA1);
- dev_priv->saveDPLL_A = I915_READ(DPLL_A);
- if (IS_I965G(dev))
- dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
- dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
- dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
- dev_priv->saveHSYNC_A = I915_READ(HSYNC_A);
- dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A);
- dev_priv->saveVBLANK_A = I915_READ(VBLANK_A);
- dev_priv->saveVSYNC_A = I915_READ(VSYNC_A);
- dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
-
- dev_priv->saveDSPACNTR = I915_READ(DSPACNTR);
- dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE);
- dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
- dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
- dev_priv->saveDSPABASE = I915_READ(DSPABASE);
- if (IS_I965G(dev)) {
- dev_priv->saveDSPASURF = I915_READ(DSPASURF);
- dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
- }
- i915_save_palette(dev, PIPE_A);
- dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT);
-
- /* Pipe & plane B info */
- dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
- dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC);
- dev_priv->saveFPB0 = I915_READ(FPB0);
- dev_priv->saveFPB1 = I915_READ(FPB1);
- dev_priv->saveDPLL_B = I915_READ(DPLL_B);
- if (IS_I965G(dev))
- dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
- dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
- dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
- dev_priv->saveHSYNC_B = I915_READ(HSYNC_B);
- dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B);
- dev_priv->saveVBLANK_B = I915_READ(VBLANK_B);
- dev_priv->saveVSYNC_B = I915_READ(VSYNC_B);
- dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
-
- dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR);
- dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE);
- dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
- dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
- dev_priv->saveDSPBBASE = I915_READ(DSPBBASE);
- if (IS_I965GM(dev) || IS_IGD_GM(dev)) {
- dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
- dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
- }
- i915_save_palette(dev, PIPE_B);
- dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT);
- /* CRT state */
- dev_priv->saveADPA = I915_READ(ADPA);
+ i915_save_state(dev);
- /* LVDS state */
- dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
- dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
- dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
- if (IS_I965G(dev))
- dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
- if (IS_MOBILE(dev) && !IS_I830(dev))
- dev_priv->saveLVDS = I915_READ(LVDS);
- if (!IS_I830(dev) && !IS_845G(dev))
- dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
- dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON);
- dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF);
- dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE);
-
- /* FIXME: save TV & SDVO state */
-
- /* FBC state */
- dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
- dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
- dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
- dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
-
- /* Interrupt state */
- dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R);
- dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R);
- dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R);
-
- /* VGA state */
- dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0);
- dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1);
- dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV);
- dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
-
- /* Clock gating state */
- dev_priv->saveD_STATE = I915_READ(D_STATE);
- dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
-
- /* Cache mode state */
- dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
-
- /* Memory Arbitration state */
- dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
-
- /* Scratch space */
- for (i = 0; i < 16; i++) {
- dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2));
- dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
- }
- for (i = 0; i < 3; i++)
- dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
-
- i915_save_vga(dev);
+ intel_opregion_free(dev);
if (state.event == PM_EVENT_SUSPEND) {
/* Shut down the device */
@@ -382,155 +68,15 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
static int i915_resume(struct drm_device *dev)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int i;
-
pci_set_power_state(dev->pdev, PCI_D0);
pci_restore_state(dev->pdev);
if (pci_enable_device(dev->pdev))
return -1;
pci_set_master(dev->pdev);
- pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
-
- I915_WRITE(DSPARB, dev_priv->saveDSPARB);
-
- /* Pipe & plane A info */
- /* Prime the clock */
- if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
- I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
- ~DPLL_VCO_ENABLE);
- udelay(150);
- }
- I915_WRITE(FPA0, dev_priv->saveFPA0);
- I915_WRITE(FPA1, dev_priv->saveFPA1);
- /* Actually enable it */
- I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
- udelay(150);
- if (IS_I965G(dev))
- I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
- udelay(150);
-
- /* Restore mode */
- I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
- I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
- I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
- I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
- I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
- I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
- I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
-
- /* Restore plane info */
- I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
- I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
- I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
- I915_WRITE(DSPABASE, dev_priv->saveDSPABASE);
- I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
- if (IS_I965G(dev)) {
- I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
- I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
- }
-
- I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
-
- i915_restore_palette(dev, PIPE_A);
- /* Enable the plane */
- I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
- I915_WRITE(DSPABASE, I915_READ(DSPABASE));
-
- /* Pipe & plane B info */
- if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
- I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
- ~DPLL_VCO_ENABLE);
- udelay(150);
- }
- I915_WRITE(FPB0, dev_priv->saveFPB0);
- I915_WRITE(FPB1, dev_priv->saveFPB1);
- /* Actually enable it */
- I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
- udelay(150);
- if (IS_I965G(dev))
- I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
- udelay(150);
-
- /* Restore mode */
- I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
- I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
- I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
- I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
- I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
- I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
- I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
-
- /* Restore plane info */
- I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
- I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
- I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
- I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE);
- I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
- if (IS_I965G(dev)) {
- I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
- I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
- }
-
- I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
-
- i915_restore_palette(dev, PIPE_B);
- /* Enable the plane */
- I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
- I915_WRITE(DSPBBASE, I915_READ(DSPBBASE));
-
- /* CRT state */
- I915_WRITE(ADPA, dev_priv->saveADPA);
-
- /* LVDS state */
- if (IS_I965G(dev))
- I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
- if (IS_MOBILE(dev) && !IS_I830(dev))
- I915_WRITE(LVDS, dev_priv->saveLVDS);
- if (!IS_I830(dev) && !IS_845G(dev))
- I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
-
- I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
- I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
- I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON);
- I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF);
- I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE);
- I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
-
- /* FIXME: restore TV & SDVO state */
-
- /* FBC info */
- I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
- I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
- I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
- I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
-
- /* VGA state */
- I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
- I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0);
- I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1);
- I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV);
- udelay(150);
-
- /* Clock gating state */
- I915_WRITE (D_STATE, dev_priv->saveD_STATE);
- I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
-
- /* Cache mode state */
- I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
-
- /* Memory arbitration state */
- I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
-
- for (i = 0; i < 16; i++) {
- I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]);
- I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
- }
- for (i = 0; i < 3; i++)
- I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
+ i915_restore_state(dev);
- i915_restore_vga(dev);
+ intel_opregion_init(dev);
return 0;
}
@@ -541,17 +87,19 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
- DRIVER_IRQ_VBL2,
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
.load = i915_driver_load,
.unload = i915_driver_unload,
+ .open = i915_driver_open,
.lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose,
+ .postclose = i915_driver_postclose,
.suspend = i915_suspend,
.resume = i915_resume,
.device_is_agp = i915_driver_device_is_agp,
- .vblank_wait = i915_driver_vblank_wait,
- .vblank_wait2 = i915_driver_vblank_wait2,
+ .get_vblank_counter = i915_get_vblank_counter,
+ .enable_vblank = i915_enable_vblank,
+ .disable_vblank = i915_disable_vblank,
.irq_preinstall = i915_driver_irq_preinstall,
.irq_postinstall = i915_driver_irq_postinstall,
.irq_uninstall = i915_driver_irq_uninstall,
@@ -559,6 +107,10 @@ static struct drm_driver driver = {
.reclaim_buffers = drm_core_reclaim_buffers,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
+ .proc_init = i915_gem_proc_init,
+ .proc_cleanup = i915_gem_proc_cleanup,
+ .gem_init_object = i915_gem_init_object,
+ .gem_free_object = i915_gem_free_object,
.ioctls = i915_ioctls,
.fops = {
.owner = THIS_MODULE,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d7326d92a23..f20ffe17df7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -30,6 +30,8 @@
#ifndef _I915_DRV_H_
#define _I915_DRV_H_
+#include "i915_reg.h"
+
/* General customization:
*/
@@ -37,7 +39,12 @@
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20060119"
+#define DRIVER_DATE "20080730"
+
+enum pipe {
+ PIPE_A = 0,
+ PIPE_B,
+};
/* Interface history:
*
@@ -53,16 +60,23 @@
#define DRIVER_MINOR 6
#define DRIVER_PATCHLEVEL 0
+#define WATCH_COHERENCY 0
+#define WATCH_BUF 0
+#define WATCH_EXEC 0
+#define WATCH_LRU 0
+#define WATCH_RELOC 0
+#define WATCH_INACTIVE 0
+#define WATCH_PWRITE 0
+
typedef struct _drm_i915_ring_buffer {
int tail_mask;
- unsigned long Start;
- unsigned long End;
unsigned long Size;
u8 *virtual_start;
int head;
int tail;
int space;
drm_local_map_t map;
+ struct drm_gem_object *ring_obj;
} drm_i915_ring_buffer_t;
struct mem_block {
@@ -80,9 +94,24 @@ typedef struct _drm_i915_vbl_swap {
unsigned int sequence;
} drm_i915_vbl_swap_t;
+struct opregion_header;
+struct opregion_acpi;
+struct opregion_swsci;
+struct opregion_asle;
+
+struct intel_opregion {
+ struct opregion_header *header;
+ struct opregion_acpi *acpi;
+ struct opregion_swsci *swsci;
+ struct opregion_asle *asle;
+ int enabled;
+};
+
typedef struct drm_i915_private {
+ struct drm_device *dev;
+
+ void __iomem *regs;
drm_local_map_t *sarea;
- drm_local_map_t *mmio_map;
drm_i915_sarea_t *sarea_priv;
drm_i915_ring_buffer_t ring;
@@ -90,20 +119,25 @@ typedef struct drm_i915_private {
drm_dma_handle_t *status_page_dmah;
void *hw_status_page;
dma_addr_t dma_status_page;
- unsigned long counter;
+ uint32_t counter;
unsigned int status_gfx_addr;
drm_local_map_t hws_map;
+ struct drm_gem_object *hws_obj;
unsigned int cpp;
int back_offset;
int front_offset;
int current_page;
int page_flipping;
- int use_mi_batchbuffer_start;
wait_queue_head_t irq_queue;
atomic_t irq_received;
- atomic_t irq_emitted;
+ /** Protects user_irq_refcount and irq_mask_reg */
+ spinlock_t user_irq_lock;
+ /** Refcount for i915_user_irq_get() versus i915_user_irq_put(). */
+ int user_irq_refcount;
+ /** Cached value of IMR to avoid reads in updating the bitfield */
+ u32 irq_mask_reg;
int tex_lru_log_granularity;
int allow_batchbuffer;
@@ -115,6 +149,8 @@ typedef struct drm_i915_private {
drm_i915_vbl_swap_t vbl_swaps;
unsigned int swaps_pending;
+ struct intel_opregion opregion;
+
/* Register state */
u8 saveLBB;
u32 saveDSPACNTR;
@@ -139,7 +175,7 @@ typedef struct drm_i915_private {
u32 saveDSPASTRIDE;
u32 saveDSPASIZE;
u32 saveDSPAPOS;
- u32 saveDSPABASE;
+ u32 saveDSPAADDR;
u32 saveDSPASURF;
u32 saveDSPATILEOFF;
u32 savePFIT_PGM_RATIOS;
@@ -160,24 +196,24 @@ typedef struct drm_i915_private {
u32 saveDSPBSTRIDE;
u32 saveDSPBSIZE;
u32 saveDSPBPOS;
- u32 saveDSPBBASE;
+ u32 saveDSPBADDR;
u32 saveDSPBSURF;
u32 saveDSPBTILEOFF;
- u32 saveVCLK_DIVISOR_VGA0;
- u32 saveVCLK_DIVISOR_VGA1;
- u32 saveVCLK_POST_DIV;
+ u32 saveVGA0;
+ u32 saveVGA1;
+ u32 saveVGA_PD;
u32 saveVGACNTRL;
u32 saveADPA;
u32 saveLVDS;
- u32 saveLVDSPP_ON;
- u32 saveLVDSPP_OFF;
+ u32 savePP_ON_DELAYS;
+ u32 savePP_OFF_DELAYS;
u32 saveDVOA;
u32 saveDVOB;
u32 saveDVOC;
u32 savePP_ON;
u32 savePP_OFF;
u32 savePP_CONTROL;
- u32 savePP_CYCLE;
+ u32 savePP_DIVISOR;
u32 savePFIT_CONTROL;
u32 save_palette_a[256];
u32 save_palette_b[256];
@@ -190,7 +226,7 @@ typedef struct drm_i915_private {
u32 saveIMR;
u32 saveCACHE_MODE_0;
u32 saveD_STATE;
- u32 saveDSPCLK_GATE_D;
+ u32 saveCG_2D_DIS;
u32 saveMI_ARB_STATE;
u32 saveSWF0[16];
u32 saveSWF1[16];
@@ -203,8 +239,180 @@ typedef struct drm_i915_private {
u8 saveDACMASK;
u8 saveDACDATA[256*3]; /* 256 3-byte colors */
u8 saveCR[37];
+
+ /** Work task for vblank-related ring access */
+ struct work_struct vblank_work;
+
+ struct {
+ struct drm_mm gtt_space;
+
+ /**
+ * List of objects currently involved in rendering from the
+ * ringbuffer.
+ *
+ * A reference is held on the buffer while on this list.
+ */
+ struct list_head active_list;
+
+ /**
+ * List of objects which are not in the ringbuffer but which
+ * still have a write_domain which needs to be flushed before
+ * unbinding.
+ *
+ * A reference is held on the buffer while on this list.
+ */
+ struct list_head flushing_list;
+
+ /**
+ * LRU list of objects which are not in the ringbuffer and
+ * are ready to unbind, but are still in the GTT.
+ *
+ * A reference is not held on the buffer while on this list,
+ * as merely being GTT-bound shouldn't prevent its being
+ * freed, and we'll pull it off the list in the free path.
+ */
+ struct list_head inactive_list;
+
+ /**
+ * List of breadcrumbs associated with GPU requests currently
+ * outstanding.
+ */
+ struct list_head request_list;
+
+ /**
+ * We leave the user IRQ off as much as possible,
+ * but this means that requests will finish and never
+ * be retired once the system goes idle. Set a timer to
+ * fire periodically while the ring is running. When it
+ * fires, go retire requests.
+ */
+ struct delayed_work retire_work;
+
+ uint32_t next_gem_seqno;
+
+ /**
+ * Waiting sequence number, if any
+ */
+ uint32_t waiting_gem_seqno;
+
+ /**
+ * Last seq seen at irq time
+ */
+ uint32_t irq_gem_seqno;
+
+ /**
+ * Flag if the X Server, and thus DRM, is not currently in
+ * control of the device.
+ *
+ * This is set between LeaveVT and EnterVT. It needs to be
+ * replaced with a semaphore. It also needs to be
+ * transitioned away from for kernel modesetting.
+ */
+ int suspended;
+
+ /**
+ * Flag if the hardware appears to be wedged.
+ *
+ * This is set when attempts to idle the device timeout.
+ * It prevents command submission from occuring and makes
+ * every pending request fail
+ */
+ int wedged;
+
+ /** Bit 6 swizzling required for X tiling */
+ uint32_t bit_6_swizzle_x;
+ /** Bit 6 swizzling required for Y tiling */
+ uint32_t bit_6_swizzle_y;
+ } mm;
} drm_i915_private_t;
+/** driver private structure attached to each drm_gem_object */
+struct drm_i915_gem_object {
+ struct drm_gem_object *obj;
+
+ /** Current space allocated to this object in the GTT, if any. */
+ struct drm_mm_node *gtt_space;
+
+ /** This object's place on the active/flushing/inactive lists */
+ struct list_head list;
+
+ /**
+ * This is set if the object is on the active or flushing lists
+ * (has pending rendering), and is not set if it's on inactive (ready
+ * to be unbound).
+ */
+ int active;
+
+ /**
+ * This is set if the object has been written to since last bound
+ * to the GTT
+ */
+ int dirty;
+
+ /** AGP memory structure for our GTT binding. */
+ DRM_AGP_MEM *agp_mem;
+
+ struct page **page_list;
+
+ /**
+ * Current offset of the object in GTT space.
+ *
+ * This is the same as gtt_space->start
+ */
+ uint32_t gtt_offset;
+
+ /** Boolean whether this object has a valid gtt offset. */
+ int gtt_bound;
+
+ /** How many users have pinned this object in GTT space */
+ int pin_count;
+
+ /** Breadcrumb of last rendering to the buffer. */
+ uint32_t last_rendering_seqno;
+
+ /** Current tiling mode for the object. */
+ uint32_t tiling_mode;
+
+ /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
+ uint32_t agp_type;
+
+ /**
+ * Flagging of which individual pages are valid in GEM_DOMAIN_CPU when
+ * GEM_DOMAIN_CPU is not in the object's read domain.
+ */
+ uint8_t *page_cpu_valid;
+};
+
+/**
+ * Request queue structure.
+ *
+ * The request queue allows us to note sequence numbers that have been emitted
+ * and may be associated with active buffers to be retired.
+ *
+ * By keeping this list, we can avoid having to do questionable
+ * sequence-number comparisons on buffer last_rendering_seqnos, and associate
+ * an emission time with seqnos for tracking how far ahead of the GPU we are.
+ */
+struct drm_i915_gem_request {
+ /** GEM sequence number associated with this request. */
+ uint32_t seqno;
+
+ /** Time at which this request was emitted, in jiffies. */
+ unsigned long emitted_jiffies;
+
+ /** Cache domains that were flushed at the start of the request. */
+ uint32_t flush_domains;
+
+ struct list_head list;
+};
+
+struct drm_i915_file_private {
+ struct {
+ uint32_t last_gem_seqno;
+ uint32_t last_gem_throttle_seqno;
+ } mm;
+};
+
extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl;
@@ -212,31 +420,42 @@ extern int i915_max_ioctl;
extern void i915_kernel_lost_context(struct drm_device * dev);
extern int i915_driver_load(struct drm_device *, unsigned long flags);
extern int i915_driver_unload(struct drm_device *);
+extern int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv);
extern void i915_driver_lastclose(struct drm_device * dev);
extern void i915_driver_preclose(struct drm_device *dev,
struct drm_file *file_priv);
+extern void i915_driver_postclose(struct drm_device *dev,
+ struct drm_file *file_priv);
extern int i915_driver_device_is_agp(struct drm_device * dev);
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
+extern int i915_emit_box(struct drm_device *dev,
+ struct drm_clip_rect __user *boxes,
+ int i, int DR1, int DR4);
/* i915_irq.c */
extern int i915_irq_emit(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_irq_wait(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+void i915_user_irq_get(struct drm_device *dev);
+void i915_user_irq_put(struct drm_device *dev);
-extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
-extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
+extern void i915_vblank_work_handler(struct work_struct *work);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(struct drm_device * dev);
-extern void i915_driver_irq_postinstall(struct drm_device * dev);
+extern int i915_driver_irq_postinstall(struct drm_device *dev);
extern void i915_driver_irq_uninstall(struct drm_device * dev);
extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+extern int i915_enable_vblank(struct drm_device *dev, int crtc);
+extern void i915_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask);
/* i915_mem.c */
extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -250,11 +469,99 @@ extern int i915_mem_destroy_heap(struct drm_device *dev, void *data,
extern void i915_mem_takedown(struct mem_block **heap);
extern void i915_mem_release(struct drm_device * dev,
struct drm_file *file_priv, struct mem_block *heap);
+/* i915_gem.c */
+int i915_gem_init_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_create_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_pread_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_execbuffer(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_pin_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_busy_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_set_tiling(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_get_tiling(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+void i915_gem_load(struct drm_device *dev);
+int i915_gem_proc_init(struct drm_minor *minor);
+void i915_gem_proc_cleanup(struct drm_minor *minor);
+int i915_gem_init_object(struct drm_gem_object *obj);
+void i915_gem_free_object(struct drm_gem_object *obj);
+int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment);
+void i915_gem_object_unpin(struct drm_gem_object *obj);
+void i915_gem_lastclose(struct drm_device *dev);
+uint32_t i915_get_gem_seqno(struct drm_device *dev);
+void i915_gem_retire_requests(struct drm_device *dev);
+void i915_gem_retire_work_handler(struct work_struct *work);
+void i915_gem_clflush_object(struct drm_gem_object *obj);
+
+/* i915_gem_tiling.c */
+void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
+
+/* i915_gem_debug.c */
+void i915_gem_dump_object(struct drm_gem_object *obj, int len,
+ const char *where, uint32_t mark);
+#if WATCH_INACTIVE
+void i915_verify_inactive(struct drm_device *dev, char *file, int line);
+#else
+#define i915_verify_inactive(dev, file, line)
+#endif
+void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle);
+void i915_gem_dump_object(struct drm_gem_object *obj, int len,
+ const char *where, uint32_t mark);
+void i915_dump_lru(struct drm_device *dev, const char *where);
+
+/* i915_suspend.c */
+extern int i915_save_state(struct drm_device *dev);
+extern int i915_restore_state(struct drm_device *dev);
+
+/* i915_suspend.c */
+extern int i915_save_state(struct drm_device *dev);
+extern int i915_restore_state(struct drm_device *dev);
+
+/* i915_opregion.c */
+extern int intel_opregion_init(struct drm_device *dev);
+extern void intel_opregion_free(struct drm_device *dev);
+extern void opregion_asle_intr(struct drm_device *dev);
+extern void opregion_enable_asle(struct drm_device *dev);
+
+/**
+ * Lock test for when it's just for synchronization of ring access.
+ *
+ * In that case, we don't need to do it when GEM is initialized as nobody else
+ * has access to the ring.
+ */
+#define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do { \
+ if (((drm_i915_private_t *)dev->dev_private)->ring.ring_obj == NULL) \
+ LOCK_TEST_WITH_RETURN(dev, file_priv); \
+} while (0)
-#define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg))
-#define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
-#define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, (reg))
-#define I915_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, (reg), (val))
+#define I915_READ(reg) readl(dev_priv->regs + (reg))
+#define I915_WRITE(reg, val) writel(val, dev_priv->regs + (reg))
+#define I915_READ16(reg) readw(dev_priv->regs + (reg))
+#define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg))
+#define I915_READ8(reg) readb(dev_priv->regs + (reg))
+#define I915_WRITE8(reg, val) writeb(val, dev_priv->regs + (reg))
#define I915_VERBOSE 0
@@ -284,816 +591,29 @@ extern void i915_mem_release(struct drm_device * dev,
if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \
dev_priv->ring.tail = outring; \
dev_priv->ring.space -= outcount * 4; \
- I915_WRITE(LP_RING + RING_TAIL, outring); \
+ I915_WRITE(PRB0_TAIL, outring); \
} while(0)
-extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
-
-/* Extended config space */
-#define LBB 0xf4
-
-/* VGA stuff */
-
-#define VGA_ST01_MDA 0x3ba
-#define VGA_ST01_CGA 0x3da
-
-#define VGA_MSR_WRITE 0x3c2
-#define VGA_MSR_READ 0x3cc
-#define VGA_MSR_MEM_EN (1<<1)
-#define VGA_MSR_CGA_MODE (1<<0)
-
-#define VGA_SR_INDEX 0x3c4
-#define VGA_SR_DATA 0x3c5
-
-#define VGA_AR_INDEX 0x3c0
-#define VGA_AR_VID_EN (1<<5)
-#define VGA_AR_DATA_WRITE 0x3c0
-#define VGA_AR_DATA_READ 0x3c1
-
-#define VGA_GR_INDEX 0x3ce
-#define VGA_GR_DATA 0x3cf
-/* GR05 */
-#define VGA_GR_MEM_READ_MODE_SHIFT 3
-#define VGA_GR_MEM_READ_MODE_PLANE 1
-/* GR06 */
-#define VGA_GR_MEM_MODE_MASK 0xc
-#define VGA_GR_MEM_MODE_SHIFT 2
-#define VGA_GR_MEM_A0000_AFFFF 0
-#define VGA_GR_MEM_A0000_BFFFF 1
-#define VGA_GR_MEM_B0000_B7FFF 2
-#define VGA_GR_MEM_B0000_BFFFF 3
-
-#define VGA_DACMASK 0x3c6
-#define VGA_DACRX 0x3c7
-#define VGA_DACWX 0x3c8
-#define VGA_DACDATA 0x3c9
-
-#define VGA_CR_INDEX_MDA 0x3b4
-#define VGA_CR_DATA_MDA 0x3b5
-#define VGA_CR_INDEX_CGA 0x3d4
-#define VGA_CR_DATA_CGA 0x3d5
-
-#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
-#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
-#define CMD_REPORT_HEAD (7<<23)
-#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1)
-#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1)
-
-#define INST_PARSER_CLIENT 0x00000000
-#define INST_OP_FLUSH 0x02000000
-#define INST_FLUSH_MAP_CACHE 0x00000001
-
-#define BB1_START_ADDR_MASK (~0x7)
-#define BB1_PROTECTED (1<<0)
-#define BB1_UNPROTECTED (0<<0)
-#define BB2_END_ADDR_MASK (~0x7)
-
-/* Framebuffer compression */
-#define FBC_CFB_BASE 0x03200 /* 4k page aligned */
-#define FBC_LL_BASE 0x03204 /* 4k page aligned */
-#define FBC_CONTROL 0x03208
-#define FBC_CTL_EN (1<<31)
-#define FBC_CTL_PERIODIC (1<<30)
-#define FBC_CTL_INTERVAL_SHIFT (16)
-#define FBC_CTL_UNCOMPRESSIBLE (1<<14)
-#define FBC_CTL_STRIDE_SHIFT (5)
-#define FBC_CTL_FENCENO (1<<0)
-#define FBC_COMMAND 0x0320c
-#define FBC_CMD_COMPRESS (1<<0)
-#define FBC_STATUS 0x03210
-#define FBC_STAT_COMPRESSING (1<<31)
-#define FBC_STAT_COMPRESSED (1<<30)
-#define FBC_STAT_MODIFIED (1<<29)
-#define FBC_STAT_CURRENT_LINE (1<<0)
-#define FBC_CONTROL2 0x03214
-#define FBC_CTL_FENCE_DBL (0<<4)
-#define FBC_CTL_IDLE_IMM (0<<2)
-#define FBC_CTL_IDLE_FULL (1<<2)
-#define FBC_CTL_IDLE_LINE (2<<2)
-#define FBC_CTL_IDLE_DEBUG (3<<2)
-#define FBC_CTL_CPU_FENCE (1<<1)
-#define FBC_CTL_PLANEA (0<<0)
-#define FBC_CTL_PLANEB (1<<0)
-#define FBC_FENCE_OFF 0x0321b
-
-#define FBC_LL_SIZE (1536)
-#define FBC_LL_PAD (32)
-
-/* Interrupt bits:
- */
-#define USER_INT_FLAG (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
-#define HWB_OOM_FLAG (1<<13) /* binner out of memory */
-
-#define I915REG_HWSTAM 0x02098
-#define I915REG_INT_IDENTITY_R 0x020a4
-#define I915REG_INT_MASK_R 0x020a8
-#define I915REG_INT_ENABLE_R 0x020a0
-
-#define I915REG_PIPEASTAT 0x70024
-#define I915REG_PIPEBSTAT 0x71024
-
-#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
-#define I915_VBLANK_CLEAR (1UL<<1)
-
-#define SRX_INDEX 0x3c4
-#define SRX_DATA 0x3c5
-#define SR01 1
-#define SR01_SCREEN_OFF (1<<5)
-
-#define PPCR 0x61204
-#define PPCR_ON (1<<0)
-
-#define DVOB 0x61140
-#define DVOB_ON (1<<31)
-#define DVOC 0x61160
-#define DVOC_ON (1<<31)
-#define LVDS 0x61180
-#define LVDS_ON (1<<31)
-
-#define ADPA 0x61100
-#define ADPA_DPMS_MASK (~(3<<10))
-#define ADPA_DPMS_ON (0<<10)
-#define ADPA_DPMS_SUSPEND (1<<10)
-#define ADPA_DPMS_STANDBY (2<<10)
-#define ADPA_DPMS_OFF (3<<10)
-
-#define NOPID 0x2094
-#define LP_RING 0x2030
-#define HP_RING 0x2040
-/* The binner has its own ring buffer:
- */
-#define HWB_RING 0x2400
-
-#define RING_TAIL 0x00
-#define TAIL_ADDR 0x001FFFF8
-#define RING_HEAD 0x04
-#define HEAD_WRAP_COUNT 0xFFE00000
-#define HEAD_WRAP_ONE 0x00200000
-#define HEAD_ADDR 0x001FFFFC
-#define RING_START 0x08
-#define START_ADDR 0x0xFFFFF000
-#define RING_LEN 0x0C
-#define RING_NR_PAGES 0x001FF000
-#define RING_REPORT_MASK 0x00000006
-#define RING_REPORT_64K 0x00000002
-#define RING_REPORT_128K 0x00000004
-#define RING_NO_REPORT 0x00000000
-#define RING_VALID_MASK 0x00000001
-#define RING_VALID 0x00000001
-#define RING_INVALID 0x00000000
-
-/* Instruction parser error reg:
- */
-#define IPEIR 0x2088
-
-/* Scratch pad debug 0 reg:
- */
-#define SCPD0 0x209c
-
-/* Error status reg:
- */
-#define ESR 0x20b8
-
-/* Secondary DMA fetch address debug reg:
- */
-#define DMA_FADD_S 0x20d4
-
-/* Memory Interface Arbitration State
- */
-#define MI_ARB_STATE 0x20e4
-
-/* Cache mode 0 reg.
- * - Manipulating render cache behaviour is central
- * to the concept of zone rendering, tuning this reg can help avoid
- * unnecessary render cache reads and even writes (for z/stencil)
- * at beginning and end of scene.
- *
- * - To change a bit, write to this reg with a mask bit set and the
- * bit of interest either set or cleared. EG: (BIT<<16) | BIT to set.
- */
-#define Cache_Mode_0 0x2120
-#define CACHE_MODE_0 0x2120
-#define CM0_MASK_SHIFT 16
-#define CM0_IZ_OPT_DISABLE (1<<6)
-#define CM0_ZR_OPT_DISABLE (1<<5)
-#define CM0_DEPTH_EVICT_DISABLE (1<<4)
-#define CM0_COLOR_EVICT_DISABLE (1<<3)
-#define CM0_DEPTH_WRITE_DISABLE (1<<1)
-#define CM0_RC_OP_FLUSH_DISABLE (1<<0)
-
-
-/* Graphics flush control. A CPU write flushes the GWB of all writes.
- * The data is discarded.
- */
-#define GFX_FLSH_CNTL 0x2170
-
-/* Binner control. Defines the location of the bin pointer list:
- */
-#define BINCTL 0x2420
-#define BC_MASK (1 << 9)
-
-/* Binned scene info.
- */
-#define BINSCENE 0x2428
-#define BS_OP_LOAD (1 << 8)
-#define BS_MASK (1 << 22)
-
-/* Bin command parser debug reg:
- */
-#define BCPD 0x2480
-
-/* Bin memory control debug reg:
- */
-#define BMCD 0x2484
-
-/* Bin data cache debug reg:
- */
-#define BDCD 0x2488
-
-/* Binner pointer cache debug reg:
- */
-#define BPCD 0x248c
-
-/* Binner scratch pad debug reg:
- */
-#define BINSKPD 0x24f0
-
-/* HWB scratch pad debug reg:
- */
-#define HWBSKPD 0x24f4
-
-/* Binner memory pool reg:
- */
-#define BMP_BUFFER 0x2430
-#define BMP_PAGE_SIZE_4K (0 << 10)
-#define BMP_BUFFER_SIZE_SHIFT 1
-#define BMP_ENABLE (1 << 0)
-
-/* Get/put memory from the binner memory pool:
- */
-#define BMP_GET 0x2438
-#define BMP_PUT 0x2440
-#define BMP_OFFSET_SHIFT 5
-
-/* 3D state packets:
- */
-#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24))
-
-#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
-#define SC_UPDATE_SCISSOR (0x1<<1)
-#define SC_ENABLE_MASK (0x1<<0)
-#define SC_ENABLE (0x1<<0)
-
-#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16))
-
-#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
-#define SCI_YMIN_MASK (0xffff<<16)
-#define SCI_XMIN_MASK (0xffff<<0)
-#define SCI_YMAX_MASK (0xffff<<16)
-#define SCI_XMAX_MASK (0xffff<<0)
-
-#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19))
-#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
-#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
-#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
-#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4)
-#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
-#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
-
-#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
-
-#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4)
-#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
-#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
-#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
-#define XY_SRC_COPY_BLT_SRC_TILED (1<<15)
-#define XY_SRC_COPY_BLT_DST_TILED (1<<11)
-
-#define MI_BATCH_BUFFER ((0x30<<23)|1)
-#define MI_BATCH_BUFFER_START (0x31<<23)
-#define MI_BATCH_BUFFER_END (0xA<<23)
-#define MI_BATCH_NON_SECURE (1)
-#define MI_BATCH_NON_SECURE_I965 (1<<8)
-
-#define MI_WAIT_FOR_EVENT ((0x3<<23))
-#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6)
-#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
-#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
-
-#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23))
-
-#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
-#define ASYNC_FLIP (1<<22)
-#define DISPLAY_PLANE_A (0<<20)
-#define DISPLAY_PLANE_B (1<<20)
-
-/* Display regs */
-#define DSPACNTR 0x70180
-#define DSPBCNTR 0x71180
-#define DISPPLANE_SEL_PIPE_MASK (1<<24)
-
-/* Define the region of interest for the binner:
- */
-#define CMD_OP_BIN_CONTROL ((0x3<<29)|(0x1d<<24)|(0x84<<16)|4)
-
-#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
-
-#define CMD_MI_FLUSH (0x04 << 23)
-#define MI_NO_WRITE_FLUSH (1 << 2)
-#define MI_READ_FLUSH (1 << 0)
-#define MI_EXE_FLUSH (1 << 1)
-#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */
-#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */
-
-#define BREADCRUMB_BITS 31
-#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1)
-
-#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5])
-#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg])
-
-#define BLC_PWM_CTL 0x61254
-#define BACKLIGHT_MODULATION_FREQ_SHIFT (17)
-
-#define BLC_PWM_CTL2 0x61250
-/**
- * This is the most significant 15 bits of the number of backlight cycles in a
- * complete cycle of the modulated backlight control.
- *
- * The actual value is this field multiplied by two.
- */
-#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17)
-#define BLM_LEGACY_MODE (1 << 16)
-/**
- * This is the number of cycles out of the backlight modulation cycle for which
- * the backlight is on.
- *
- * This field must be no greater than the number of cycles in the complete
- * backlight modulation cycle.
- */
-#define BACKLIGHT_DUTY_CYCLE_SHIFT (0)
-#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff)
-
-#define I915_GCFGC 0xf0
-#define I915_LOW_FREQUENCY_ENABLE (1 << 7)
-#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
-#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4)
-#define I915_DISPLAY_CLOCK_MASK (7 << 4)
-
-#define I855_HPLLCC 0xc0
-#define I855_CLOCK_CONTROL_MASK (3 << 0)
-#define I855_CLOCK_133_200 (0 << 0)
-#define I855_CLOCK_100_200 (1 << 0)
-#define I855_CLOCK_100_133 (2 << 0)
-#define I855_CLOCK_166_250 (3 << 0)
-
-/* p317, 319
- */
-#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */
-#define VCLK2_VCO_N 0x600a
-#define VCLK2_VCO_DIV_SEL 0x6012
-
-#define VCLK_DIVISOR_VGA0 0x6000
-#define VCLK_DIVISOR_VGA1 0x6004
-#define VCLK_POST_DIV 0x6010
-/** Selects a post divisor of 4 instead of 2. */
-# define VGA1_PD_P2_DIV_4 (1 << 15)
-/** Overrides the p2 post divisor field */
-# define VGA1_PD_P1_DIV_2 (1 << 13)
-# define VGA1_PD_P1_SHIFT 8
-/** P1 value is 2 greater than this field */
-# define VGA1_PD_P1_MASK (0x1f << 8)
-/** Selects a post divisor of 4 instead of 2. */
-# define VGA0_PD_P2_DIV_4 (1 << 7)
-/** Overrides the p2 post divisor field */
-# define VGA0_PD_P1_DIV_2 (1 << 5)
-# define VGA0_PD_P1_SHIFT 0
-/** P1 value is 2 greater than this field */
-# define VGA0_PD_P1_MASK (0x1f << 0)
-
-/* PCI D state control register */
-#define D_STATE 0x6104
-#define DSPCLK_GATE_D 0x6200
-
-/* I830 CRTC registers */
-#define HTOTAL_A 0x60000
-#define HBLANK_A 0x60004
-#define HSYNC_A 0x60008
-#define VTOTAL_A 0x6000c
-#define VBLANK_A 0x60010
-#define VSYNC_A 0x60014
-#define PIPEASRC 0x6001c
-#define BCLRPAT_A 0x60020
-#define VSYNCSHIFT_A 0x60028
-
-#define HTOTAL_B 0x61000
-#define HBLANK_B 0x61004
-#define HSYNC_B 0x61008
-#define VTOTAL_B 0x6100c
-#define VBLANK_B 0x61010
-#define VSYNC_B 0x61014
-#define PIPEBSRC 0x6101c
-#define BCLRPAT_B 0x61020
-#define VSYNCSHIFT_B 0x61028
-
-#define PP_STATUS 0x61200
-# define PP_ON (1 << 31)
-/**
- * Indicates that all dependencies of the panel are on:
- *
- * - PLL enabled
- * - pipe enabled
- * - LVDS/DVOB/DVOC on
- */
-# define PP_READY (1 << 30)
-# define PP_SEQUENCE_NONE (0 << 28)
-# define PP_SEQUENCE_ON (1 << 28)
-# define PP_SEQUENCE_OFF (2 << 28)
-# define PP_SEQUENCE_MASK 0x30000000
-#define PP_CONTROL 0x61204
-# define POWER_TARGET_ON (1 << 0)
-
-#define LVDSPP_ON 0x61208
-#define LVDSPP_OFF 0x6120c
-#define PP_CYCLE 0x61210
-
-#define PFIT_CONTROL 0x61230
-# define PFIT_ENABLE (1 << 31)
-# define PFIT_PIPE_MASK (3 << 29)
-# define PFIT_PIPE_SHIFT 29
-# define VERT_INTERP_DISABLE (0 << 10)
-# define VERT_INTERP_BILINEAR (1 << 10)
-# define VERT_INTERP_MASK (3 << 10)
-# define VERT_AUTO_SCALE (1 << 9)
-# define HORIZ_INTERP_DISABLE (0 << 6)
-# define HORIZ_INTERP_BILINEAR (1 << 6)
-# define HORIZ_INTERP_MASK (3 << 6)
-# define HORIZ_AUTO_SCALE (1 << 5)
-# define PANEL_8TO6_DITHER_ENABLE (1 << 3)
-
-#define PFIT_PGM_RATIOS 0x61234
-# define PFIT_VERT_SCALE_MASK 0xfff00000
-# define PFIT_HORIZ_SCALE_MASK 0x0000fff0
-
-#define PFIT_AUTO_RATIOS 0x61238
-
-
-#define DPLL_A 0x06014
-#define DPLL_B 0x06018
-# define DPLL_VCO_ENABLE (1 << 31)
-# define DPLL_DVO_HIGH_SPEED (1 << 30)
-# define DPLL_SYNCLOCK_ENABLE (1 << 29)
-# define DPLL_VGA_MODE_DIS (1 << 28)
-# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */
-# define DPLLB_MODE_LVDS (2 << 26) /* i915 */
-# define DPLL_MODE_MASK (3 << 26)
-# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */
-# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */
-# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */
-# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */
-# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
-# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
-/**
- * The i830 generation, in DAC/serial mode, defines p1 as two plus this
- * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set.
- */
-# define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000
-/**
- * The i830 generation, in LVDS mode, defines P1 as the bit number set within
- * this field (only one bit may be set).
- */
-# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000
-# define DPLL_FPA01_P1_POST_DIV_SHIFT 16
-# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */
-# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */
-# define PLL_REF_INPUT_DREFCLK (0 << 13)
-# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */
-# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */
-# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
-# define PLL_REF_INPUT_MASK (3 << 13)
-# define PLL_LOAD_PULSE_PHASE_SHIFT 9
-/*
- * Parallel to Serial Load Pulse phase selection.
- * Selects the phase for the 10X DPLL clock for the PCIe
- * digital display port. The range is 4 to 13; 10 or more
- * is just a flip delay. The default is 6
- */
-# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
-# define DISPLAY_RATE_SELECT_FPA1 (1 << 8)
-
-/**
- * SDVO multiplier for 945G/GM. Not used on 965.
- *
- * \sa DPLL_MD_UDI_MULTIPLIER_MASK
- */
-# define SDVO_MULTIPLIER_MASK 0x000000ff
-# define SDVO_MULTIPLIER_SHIFT_HIRES 4
-# define SDVO_MULTIPLIER_SHIFT_VGA 0
-
-/** @defgroup DPLL_MD
- * @{
- */
-/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */
-#define DPLL_A_MD 0x0601c
-/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */
-#define DPLL_B_MD 0x06020
-/**
- * UDI pixel divider, controlling how many pixels are stuffed into a packet.
- *
- * Value is pixels minus 1. Must be set to 1 pixel for SDVO.
- */
-# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000
-# define DPLL_MD_UDI_DIVIDER_SHIFT 24
-/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */
-# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000
-# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16
-/**
- * SDVO/UDI pixel multiplier.
- *
- * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus
- * clock rate is 10 times the DPLL clock. At low resolution/refresh rate
- * modes, the bus rate would be below the limits, so SDVO allows for stuffing
- * dummy bytes in the datastream at an increased clock rate, with both sides of
- * the link knowing how many bytes are fill.
- *
- * So, for a mode with a dotclock of 65Mhz, we would want to double the clock
- * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be
- * set to 130Mhz, and the SDVO multiplier set to 2x in this register and
- * through an SDVO command.
- *
- * This register field has values of multiplication factor minus 1, with
- * a maximum multiplier of 5 for SDVO.
- */
-# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00
-# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8
-/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK.
- * This best be set to the default value (3) or the CRT won't work. No,
- * I don't entirely understand what this does...
- */
-# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f
-# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0
-/** @} */
-
-#define DPLL_TEST 0x606c
-# define DPLLB_TEST_SDVO_DIV_1 (0 << 22)
-# define DPLLB_TEST_SDVO_DIV_2 (1 << 22)
-# define DPLLB_TEST_SDVO_DIV_4 (2 << 22)
-# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22)
-# define DPLLB_TEST_N_BYPASS (1 << 19)
-# define DPLLB_TEST_M_BYPASS (1 << 18)
-# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16)
-# define DPLLA_TEST_N_BYPASS (1 << 3)
-# define DPLLA_TEST_M_BYPASS (1 << 2)
-# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0)
-
-#define ADPA 0x61100
-#define ADPA_DAC_ENABLE (1<<31)
-#define ADPA_DAC_DISABLE 0
-#define ADPA_PIPE_SELECT_MASK (1<<30)
-#define ADPA_PIPE_A_SELECT 0
-#define ADPA_PIPE_B_SELECT (1<<30)
-#define ADPA_USE_VGA_HVPOLARITY (1<<15)
-#define ADPA_SETS_HVPOLARITY 0
-#define ADPA_VSYNC_CNTL_DISABLE (1<<11)
-#define ADPA_VSYNC_CNTL_ENABLE 0
-#define ADPA_HSYNC_CNTL_DISABLE (1<<10)
-#define ADPA_HSYNC_CNTL_ENABLE 0
-#define ADPA_VSYNC_ACTIVE_HIGH (1<<4)
-#define ADPA_VSYNC_ACTIVE_LOW 0
-#define ADPA_HSYNC_ACTIVE_HIGH (1<<3)
-#define ADPA_HSYNC_ACTIVE_LOW 0
-
-#define FPA0 0x06040
-#define FPA1 0x06044
-#define FPB0 0x06048
-#define FPB1 0x0604c
-# define FP_N_DIV_MASK 0x003f0000
-# define FP_N_DIV_SHIFT 16
-# define FP_M1_DIV_MASK 0x00003f00
-# define FP_M1_DIV_SHIFT 8
-# define FP_M2_DIV_MASK 0x0000003f
-# define FP_M2_DIV_SHIFT 0
-
-
-#define PORT_HOTPLUG_EN 0x61110
-# define SDVOB_HOTPLUG_INT_EN (1 << 26)
-# define SDVOC_HOTPLUG_INT_EN (1 << 25)
-# define TV_HOTPLUG_INT_EN (1 << 18)
-# define CRT_HOTPLUG_INT_EN (1 << 9)
-# define CRT_HOTPLUG_FORCE_DETECT (1 << 3)
-
-#define PORT_HOTPLUG_STAT 0x61114
-# define CRT_HOTPLUG_INT_STATUS (1 << 11)
-# define TV_HOTPLUG_INT_STATUS (1 << 10)
-# define CRT_HOTPLUG_MONITOR_MASK (3 << 8)
-# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8)
-# define CRT_HOTPLUG_MONITOR_MONO (2 << 8)
-# define CRT_HOTPLUG_MONITOR_NONE (0 << 8)
-# define SDVOC_HOTPLUG_INT_STATUS (1 << 7)
-# define SDVOB_HOTPLUG_INT_STATUS (1 << 6)
-
-#define SDVOB 0x61140
-#define SDVOC 0x61160
-#define SDVO_ENABLE (1 << 31)
-#define SDVO_PIPE_B_SELECT (1 << 30)
-#define SDVO_STALL_SELECT (1 << 29)
-#define SDVO_INTERRUPT_ENABLE (1 << 26)
/**
- * 915G/GM SDVO pixel multiplier.
+ * Reads a dword out of the status page, which is written to from the command
+ * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
+ * MI_STORE_DATA_IMM.
*
- * Programmed value is multiplier - 1, up to 5x.
- *
- * \sa DPLL_MD_UDI_MULTIPLIER_MASK
- */
-#define SDVO_PORT_MULTIPLY_MASK (7 << 23)
-#define SDVO_PORT_MULTIPLY_SHIFT 23
-#define SDVO_PHASE_SELECT_MASK (15 << 19)
-#define SDVO_PHASE_SELECT_DEFAULT (6 << 19)
-#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18)
-#define SDVOC_GANG_MODE (1 << 16)
-#define SDVO_BORDER_ENABLE (1 << 7)
-#define SDVOB_PCIE_CONCURRENCY (1 << 3)
-#define SDVO_DETECTED (1 << 2)
-/* Bits to be preserved when writing */
-#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14))
-#define SDVOC_PRESERVE_MASK (1 << 17)
-
-/** @defgroup LVDS
- * @{
- */
-/**
- * This register controls the LVDS output enable, pipe selection, and data
- * format selection.
+ * The following dwords have a reserved meaning:
+ * 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes.
+ * 0x04: ring 0 head pointer
+ * 0x05: ring 1 head pointer (915-class)
+ * 0x06: ring 2 head pointer (915-class)
+ * 0x10-0x1b: Context status DWords (GM45)
+ * 0x1f: Last written status offset. (GM45)
*
- * All of the clock/data pairs are force powered down by power sequencing.
- */
-#define LVDS 0x61180
-/**
- * Enables the LVDS port. This bit must be set before DPLLs are enabled, as
- * the DPLL semantics change when the LVDS is assigned to that pipe.
- */
-# define LVDS_PORT_EN (1 << 31)
-/** Selects pipe B for LVDS data. Must be set on pre-965. */
-# define LVDS_PIPEB_SELECT (1 << 30)
-
-/**
- * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per
- * pixel.
- */
-# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8)
-# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8)
-# define LVDS_A0A2_CLKA_POWER_UP (3 << 8)
-/**
- * Controls the A3 data pair, which contains the additional LSBs for 24 bit
- * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be
- * on.
- */
-# define LVDS_A3_POWER_MASK (3 << 6)
-# define LVDS_A3_POWER_DOWN (0 << 6)
-# define LVDS_A3_POWER_UP (3 << 6)
-/**
- * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP
- * is set.
- */
-# define LVDS_CLKB_POWER_MASK (3 << 4)
-# define LVDS_CLKB_POWER_DOWN (0 << 4)
-# define LVDS_CLKB_POWER_UP (3 << 4)
-
-/**
- * Controls the B0-B3 data pairs. This must be set to match the DPLL p2
- * setting for whether we are in dual-channel mode. The B3 pair will
- * additionally only be powered up when LVDS_A3_POWER_UP is set.
- */
-# define LVDS_B0B3_POWER_MASK (3 << 2)
-# define LVDS_B0B3_POWER_DOWN (0 << 2)
-# define LVDS_B0B3_POWER_UP (3 << 2)
-
-#define PIPEACONF 0x70008
-#define PIPEACONF_ENABLE (1<<31)
-#define PIPEACONF_DISABLE 0
-#define PIPEACONF_DOUBLE_WIDE (1<<30)
-#define I965_PIPECONF_ACTIVE (1<<30)
-#define PIPEACONF_SINGLE_WIDE 0
-#define PIPEACONF_PIPE_UNLOCKED 0
-#define PIPEACONF_PIPE_LOCKED (1<<25)
-#define PIPEACONF_PALETTE 0
-#define PIPEACONF_GAMMA (1<<24)
-#define PIPECONF_FORCE_BORDER (1<<25)
-#define PIPECONF_PROGRESSIVE (0 << 21)
-#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
-#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
-
-#define DSPARB 0x70030
-#define DSPARB_CSTART_MASK (0x7f << 7)
-#define DSPARB_CSTART_SHIFT 7
-#define DSPARB_BSTART_MASK (0x7f)
-#define DSPARB_BSTART_SHIFT 0
-
-#define PIPEBCONF 0x71008
-#define PIPEBCONF_ENABLE (1<<31)
-#define PIPEBCONF_DISABLE 0
-#define PIPEBCONF_DOUBLE_WIDE (1<<30)
-#define PIPEBCONF_DISABLE 0
-#define PIPEBCONF_GAMMA (1<<24)
-#define PIPEBCONF_PALETTE 0
-
-#define PIPEBGCMAXRED 0x71010
-#define PIPEBGCMAXGREEN 0x71014
-#define PIPEBGCMAXBLUE 0x71018
-#define PIPEBSTAT 0x71024
-#define PIPEBFRAMEHIGH 0x71040
-#define PIPEBFRAMEPIXEL 0x71044
-
-#define DSPACNTR 0x70180
-#define DSPBCNTR 0x71180
-#define DISPLAY_PLANE_ENABLE (1<<31)
-#define DISPLAY_PLANE_DISABLE 0
-#define DISPPLANE_GAMMA_ENABLE (1<<30)
-#define DISPPLANE_GAMMA_DISABLE 0
-#define DISPPLANE_PIXFORMAT_MASK (0xf<<26)
-#define DISPPLANE_8BPP (0x2<<26)
-#define DISPPLANE_15_16BPP (0x4<<26)
-#define DISPPLANE_16BPP (0x5<<26)
-#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26)
-#define DISPPLANE_32BPP (0x7<<26)
-#define DISPPLANE_STEREO_ENABLE (1<<25)
-#define DISPPLANE_STEREO_DISABLE 0
-#define DISPPLANE_SEL_PIPE_MASK (1<<24)
-#define DISPPLANE_SEL_PIPE_A 0
-#define DISPPLANE_SEL_PIPE_B (1<<24)
-#define DISPPLANE_SRC_KEY_ENABLE (1<<22)
-#define DISPPLANE_SRC_KEY_DISABLE 0
-#define DISPPLANE_LINE_DOUBLE (1<<20)
-#define DISPPLANE_NO_LINE_DOUBLE 0
-#define DISPPLANE_STEREO_POLARITY_FIRST 0
-#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
-/* plane B only */
-#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15)
-#define DISPPLANE_ALPHA_TRANS_DISABLE 0
-#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0
-#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1)
-
-#define DSPABASE 0x70184
-#define DSPASTRIDE 0x70188
-
-#define DSPBBASE 0x71184
-#define DSPBADDR DSPBBASE
-#define DSPBSTRIDE 0x71188
-
-#define DSPAKEYVAL 0x70194
-#define DSPAKEYMASK 0x70198
-
-#define DSPAPOS 0x7018C /* reserved */
-#define DSPASIZE 0x70190
-#define DSPBPOS 0x7118C
-#define DSPBSIZE 0x71190
-
-#define DSPASURF 0x7019C
-#define DSPATILEOFF 0x701A4
-
-#define DSPBSURF 0x7119C
-#define DSPBTILEOFF 0x711A4
-
-#define VGACNTRL 0x71400
-# define VGA_DISP_DISABLE (1 << 31)
-# define VGA_2X_MODE (1 << 30)
-# define VGA_PIPE_B_SELECT (1 << 29)
-
-/*
- * Some BIOS scratch area registers. The 845 (and 830?) store the amount
- * of video memory available to the BIOS in SWF1.
- */
-
-#define SWF0 0x71410
-
-/*
- * 855 scratch registers.
- */
-#define SWF10 0x70410
-
-#define SWF30 0x72414
-
-/*
- * Overlay registers. These are overlay registers accessed via MMIO.
- * Those loaded via the overlay register page are defined in i830_video.c.
+ * The area from dword 0x20 to 0x3ff is available for driver usage.
*/
-#define OVADD 0x30000
-
-#define DOVSTA 0x30008
-#define OC_BUF (0x3<<20)
+#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg])
+#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, 5)
+#define I915_GEM_HWS_INDEX 0x20
-#define OGAMC5 0x30010
-#define OGAMC4 0x30014
-#define OGAMC3 0x30018
-#define OGAMC2 0x3001c
-#define OGAMC1 0x30020
-#define OGAMC0 0x30024
-/*
- * Palette registers
- */
-#define PALETTE_A 0x0a000
-#define PALETTE_B 0x0a800
+extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_I830(dev) ((dev)->pci_device == 0x3577)
#define IS_845G(dev) ((dev)->pci_device == 0x2562)
@@ -1119,7 +639,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_I965GM(dev) ((dev)->pci_device == 0x2A02)
-#define IS_IGD_GM(dev) ((dev)->pci_device == 0x2A42)
+#define IS_GM45(dev) ((dev)->pci_device == 0x2A42)
#define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \
(dev)->pci_device == 0x2E12 || \
@@ -1133,9 +653,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev))
#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
- IS_I945GM(dev) || IS_I965GM(dev) || IS_IGD_GM(dev))
+ IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev))
-#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev) || IS_G4X(dev))
+#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev))
#define PRIMARY_RINGBUFFER_SIZE (128*1024)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
new file mode 100644
index 00000000000..17ae330ff26
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -0,0 +1,2570 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include <linux/swap.h>
+
+static int
+i915_gem_object_set_domain(struct drm_gem_object *obj,
+ uint32_t read_domains,
+ uint32_t write_domain);
+static int
+i915_gem_object_set_domain_range(struct drm_gem_object *obj,
+ uint64_t offset,
+ uint64_t size,
+ uint32_t read_domains,
+ uint32_t write_domain);
+static int
+i915_gem_set_domain(struct drm_gem_object *obj,
+ struct drm_file *file_priv,
+ uint32_t read_domains,
+ uint32_t write_domain);
+static int i915_gem_object_get_page_list(struct drm_gem_object *obj);
+static void i915_gem_object_free_page_list(struct drm_gem_object *obj);
+static int i915_gem_object_wait_rendering(struct drm_gem_object *obj);
+
+static void
+i915_gem_cleanup_ringbuffer(struct drm_device *dev);
+
+int
+i915_gem_init_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_init *args = data;
+
+ mutex_lock(&dev->struct_mutex);
+
+ if (args->gtt_start >= args->gtt_end ||
+ (args->gtt_start & (PAGE_SIZE - 1)) != 0 ||
+ (args->gtt_end & (PAGE_SIZE - 1)) != 0) {
+ mutex_unlock(&dev->struct_mutex);
+ return -EINVAL;
+ }
+
+ drm_mm_init(&dev_priv->mm.gtt_space, args->gtt_start,
+ args->gtt_end - args->gtt_start);
+
+ dev->gtt_total = (uint32_t) (args->gtt_end - args->gtt_start);
+
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+
+/**
+ * Creates a new mm object and returns a handle to it.
+ */
+int
+i915_gem_create_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_create *args = data;
+ struct drm_gem_object *obj;
+ int handle, ret;
+
+ args->size = roundup(args->size, PAGE_SIZE);
+
+ /* Allocate the new object */
+ obj = drm_gem_object_alloc(dev, args->size);
+ if (obj == NULL)
+ return -ENOMEM;
+
+ ret = drm_gem_handle_create(file_priv, obj, &handle);
+ mutex_lock(&dev->struct_mutex);
+ drm_gem_object_handle_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+
+ if (ret)
+ return ret;
+
+ args->handle = handle;
+
+ return 0;
+}
+
+/**
+ * Reads data from the object referenced by handle.
+ *
+ * On error, the contents of *data are undefined.
+ */
+int
+i915_gem_pread_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_pread *args = data;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ ssize_t read;
+ loff_t offset;
+ int ret;
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL)
+ return -EBADF;
+ obj_priv = obj->driver_private;
+
+ /* Bounds check source.
+ *
+ * XXX: This could use review for overflow issues...
+ */
+ if (args->offset > obj->size || args->size > obj->size ||
+ args->offset + args->size > obj->size) {
+ drm_gem_object_unreference(obj);
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->struct_mutex);
+
+ ret = i915_gem_object_set_domain_range(obj, args->offset, args->size,
+ I915_GEM_DOMAIN_CPU, 0);
+ if (ret != 0) {
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+
+ offset = args->offset;
+
+ read = vfs_read(obj->filp, (char __user *)(uintptr_t)args->data_ptr,
+ args->size, &offset);
+ if (read != args->size) {
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ if (read < 0)
+ return read;
+ else
+ return -EINVAL;
+ }
+
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+/*
+ * Try to write quickly with an atomic kmap. Return true on success.
+ *
+ * If this fails (which includes a partial write), we'll redo the whole
+ * thing with the slow version.
+ *
+ * This is a workaround for the low performance of iounmap (approximate
+ * 10% cpu cost on normal 3D workloads). kmap_atomic on HIGHMEM kernels
+ * happens to let us map card memory without taking IPIs. When the vmap
+ * rework lands we should be able to dump this hack.
+ */
+static inline int fast_user_write(unsigned long pfn, char __user *user_data,
+ int l, int o)
+{
+#ifdef CONFIG_HIGHMEM
+ unsigned long unwritten;
+ char *vaddr_atomic;
+
+ vaddr_atomic = kmap_atomic_pfn(pfn, KM_USER0);
+#if WATCH_PWRITE
+ DRM_INFO("pwrite i %d o %d l %d pfn %ld vaddr %p\n",
+ i, o, l, pfn, vaddr_atomic);
+#endif
+ unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + o, user_data, l);
+ kunmap_atomic(vaddr_atomic, KM_USER0);
+ return !unwritten;
+#else
+ return 0;
+#endif
+}
+
+static int
+i915_gem_gtt_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;
+ ssize_t remain;
+ loff_t offset;
+ char __user *user_data;
+ int ret = 0;
+
+ user_data = (char __user *) (uintptr_t) args->data_ptr;
+ remain = args->size;
+ if (!access_ok(VERIFY_READ, user_data, remain))
+ return -EFAULT;
+
+
+ mutex_lock(&dev->struct_mutex);
+ ret = i915_gem_object_pin(obj, 0);
+ if (ret) {
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+ ret = i915_gem_set_domain(obj, file_priv,
+ I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ if (ret)
+ goto fail;
+
+ obj_priv = obj->driver_private;
+ offset = obj_priv->gtt_offset + args->offset;
+ obj_priv->dirty = 1;
+
+ while (remain > 0) {
+ unsigned long pfn;
+ int i, o, l;
+
+ /* Operation in this page
+ *
+ * i = page number
+ * o = offset within page
+ * l = bytes to copy
+ */
+ i = offset >> PAGE_SHIFT;
+ o = offset & (PAGE_SIZE-1);
+ l = remain;
+ if ((o + l) > PAGE_SIZE)
+ l = PAGE_SIZE - o;
+
+ pfn = (dev->agp->base >> PAGE_SHIFT) + i;
+
+ if (!fast_user_write(pfn, user_data, l, o)) {
+ unsigned long unwritten;
+ char __iomem *vaddr;
+
+ vaddr = ioremap_wc(pfn << PAGE_SHIFT, PAGE_SIZE);
+#if WATCH_PWRITE
+ DRM_INFO("pwrite slow i %d o %d l %d "
+ "pfn %ld vaddr %p\n",
+ i, o, l, pfn, vaddr);
+#endif
+ if (vaddr == NULL) {
+ ret = -EFAULT;
+ goto fail;
+ }
+ unwritten = __copy_from_user(vaddr + o, user_data, l);
+#if WATCH_PWRITE
+ DRM_INFO("unwritten %ld\n", unwritten);
+#endif
+ iounmap(vaddr);
+ if (unwritten) {
+ ret = -EFAULT;
+ goto fail;
+ }
+ }
+
+ remain -= l;
+ user_data += l;
+ offset += l;
+ }
+#if WATCH_PWRITE && 1
+ i915_gem_clflush_object(obj);
+ i915_gem_dump_object(obj, args->offset + args->size, __func__, ~0);
+ i915_gem_clflush_object(obj);
+#endif
+
+fail:
+ i915_gem_object_unpin(obj);
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
+}
+
+static int
+i915_gem_shmem_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
+ struct drm_i915_gem_pwrite *args,
+ struct drm_file *file_priv)
+{
+ int ret;
+ loff_t offset;
+ ssize_t written;
+
+ mutex_lock(&dev->struct_mutex);
+
+ ret = i915_gem_set_domain(obj, file_priv,
+ I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+ if (ret) {
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+
+ offset = args->offset;
+
+ written = vfs_write(obj->filp,
+ (char __user *)(uintptr_t) args->data_ptr,
+ args->size, &offset);
+ if (written != args->size) {
+ mutex_unlock(&dev->struct_mutex);
+ if (written < 0)
+ return written;
+ else
+ return -EINVAL;
+ }
+
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+/**
+ * Writes data to the object referenced by handle.
+ *
+ * On error, the contents of the buffer that were to be modified are undefined.
+ */
+int
+i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_pwrite *args = data;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ int ret = 0;
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL)
+ return -EBADF;
+ obj_priv = obj->driver_private;
+
+ /* Bounds check destination.
+ *
+ * XXX: This could use review for overflow issues...
+ */
+ if (args->offset > obj->size || args->size > obj->size ||
+ args->offset + args->size > obj->size) {
+ drm_gem_object_unreference(obj);
+ return -EINVAL;
+ }
+
+ /* We can only do the GTT pwrite on untiled buffers, as otherwise
+ * it would end up going through the fenced access, and we'll get
+ * different detiling behavior between reading and writing.
+ * 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)
+ ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
+ else
+ ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv);
+
+#if WATCH_PWRITE
+ if (ret)
+ DRM_INFO("pwrite failed %d\n", ret);
+#endif
+
+ drm_gem_object_unreference(obj);
+
+ return ret;
+}
+
+/**
+ * Called when user space prepares to use an object
+ */
+int
+i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_set_domain *args = data;
+ struct drm_gem_object *obj;
+ int ret;
+
+ if (!(dev->driver->driver_features & DRIVER_GEM))
+ return -ENODEV;
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL)
+ return -EBADF;
+
+ mutex_lock(&dev->struct_mutex);
+#if WATCH_BUF
+ DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n",
+ obj, obj->size, args->read_domains, args->write_domain);
+#endif
+ ret = i915_gem_set_domain(obj, file_priv,
+ args->read_domains, args->write_domain);
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+}
+
+/**
+ * Called when user space has done writes to this buffer
+ */
+int
+i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_sw_finish *args = data;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ int ret = 0;
+
+ if (!(dev->driver->driver_features & DRIVER_GEM))
+ return -ENODEV;
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL) {
+ mutex_unlock(&dev->struct_mutex);
+ return -EBADF;
+ }
+
+#if WATCH_BUF
+ DRM_INFO("%s: sw_finish %d (%p %d)\n",
+ __func__, args->handle, obj, obj->size);
+#endif
+ obj_priv = obj->driver_private;
+
+ /* Pinned buffers may be scanout, so flush the cache */
+ if ((obj->write_domain & I915_GEM_DOMAIN_CPU) && obj_priv->pin_count) {
+ i915_gem_clflush_object(obj);
+ drm_agp_chipset_flush(dev);
+ }
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+}
+
+/**
+ * Maps the contents of an object, returning the address it is mapped
+ * into.
+ *
+ * While the mapping holds a reference on the contents of the object, it doesn't
+ * imply a ref on the object itself.
+ */
+int
+i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_mmap *args = data;
+ struct drm_gem_object *obj;
+ loff_t offset;
+ unsigned long addr;
+
+ if (!(dev->driver->driver_features & DRIVER_GEM))
+ return -ENODEV;
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL)
+ return -EBADF;
+
+ offset = args->offset;
+
+ down_write(&current->mm->mmap_sem);
+ addr = do_mmap(obj->filp, 0, args->size,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ args->offset);
+ up_write(&current->mm->mmap_sem);
+ mutex_lock(&dev->struct_mutex);
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ if (IS_ERR((void *)addr))
+ return addr;
+
+ args->addr_ptr = (uint64_t) addr;
+
+ return 0;
+}
+
+static void
+i915_gem_object_free_page_list(struct drm_gem_object *obj)
+{
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int page_count = obj->size / PAGE_SIZE;
+ int i;
+
+ if (obj_priv->page_list == NULL)
+ return;
+
+
+ for (i = 0; i < page_count; i++)
+ if (obj_priv->page_list[i] != NULL) {
+ if (obj_priv->dirty)
+ set_page_dirty(obj_priv->page_list[i]);
+ mark_page_accessed(obj_priv->page_list[i]);
+ page_cache_release(obj_priv->page_list[i]);
+ }
+ obj_priv->dirty = 0;
+
+ drm_free(obj_priv->page_list,
+ page_count * sizeof(struct page *),
+ DRM_MEM_DRIVER);
+ obj_priv->page_list = NULL;
+}
+
+static void
+i915_gem_object_move_to_active(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ /* Add a reference if we're newly entering the active list. */
+ if (!obj_priv->active) {
+ drm_gem_object_reference(obj);
+ obj_priv->active = 1;
+ }
+ /* Move from whatever list we were on to the tail of execution. */
+ list_move_tail(&obj_priv->list,
+ &dev_priv->mm.active_list);
+}
+
+
+static void
+i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+ if (obj_priv->pin_count != 0)
+ list_del_init(&obj_priv->list);
+ else
+ list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+
+ if (obj_priv->active) {
+ obj_priv->active = 0;
+ drm_gem_object_unreference(obj);
+ }
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+}
+
+/**
+ * Creates a new sequence number, emitting a write of it to the status page
+ * plus an interrupt, which will trigger i915_user_interrupt_handler.
+ *
+ * Must be called with struct_lock held.
+ *
+ * Returned sequence numbers are nonzero on success.
+ */
+static uint32_t
+i915_add_request(struct drm_device *dev, uint32_t flush_domains)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_request *request;
+ uint32_t seqno;
+ int was_empty;
+ RING_LOCALS;
+
+ request = drm_calloc(1, sizeof(*request), DRM_MEM_DRIVER);
+ if (request == NULL)
+ return 0;
+
+ /* Grab the seqno we're going to make this request be, and bump the
+ * next (skipping 0 so it can be the reserved no-seqno value).
+ */
+ seqno = dev_priv->mm.next_gem_seqno;
+ dev_priv->mm.next_gem_seqno++;
+ if (dev_priv->mm.next_gem_seqno == 0)
+ dev_priv->mm.next_gem_seqno++;
+
+ BEGIN_LP_RING(4);
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ OUT_RING(seqno);
+
+ OUT_RING(MI_USER_INTERRUPT);
+ ADVANCE_LP_RING();
+
+ DRM_DEBUG("%d\n", seqno);
+
+ request->seqno = seqno;
+ request->emitted_jiffies = jiffies;
+ request->flush_domains = flush_domains;
+ was_empty = list_empty(&dev_priv->mm.request_list);
+ list_add_tail(&request->list, &dev_priv->mm.request_list);
+
+ if (was_empty && !dev_priv->mm.suspended)
+ schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
+ return seqno;
+}
+
+/**
+ * Command execution barrier
+ *
+ * Ensures that all commands in the ring are finished
+ * before signalling the CPU
+ */
+static uint32_t
+i915_retire_commands(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ uint32_t cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
+ uint32_t flush_domains = 0;
+ RING_LOCALS;
+
+ /* The sampler always gets flushed on i965 (sigh) */
+ if (IS_I965G(dev))
+ flush_domains |= I915_GEM_DOMAIN_SAMPLER;
+ BEGIN_LP_RING(2);
+ OUT_RING(cmd);
+ OUT_RING(0); /* noop */
+ ADVANCE_LP_RING();
+ return flush_domains;
+}
+
+/**
+ * Moves buffers associated only with the given active seqno from the active
+ * to inactive list, potentially freeing them.
+ */
+static void
+i915_gem_retire_request(struct drm_device *dev,
+ struct drm_i915_gem_request *request)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ /* Move any buffers on the active list that are no longer referenced
+ * by the ringbuffer to the flushing/inactive lists as appropriate.
+ */
+ while (!list_empty(&dev_priv->mm.active_list)) {
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+
+ obj_priv = list_first_entry(&dev_priv->mm.active_list,
+ struct drm_i915_gem_object,
+ list);
+ obj = obj_priv->obj;
+
+ /* If the seqno being retired doesn't match the oldest in the
+ * list, then the oldest in the list must still be newer than
+ * this seqno.
+ */
+ if (obj_priv->last_rendering_seqno != request->seqno)
+ return;
+#if WATCH_LRU
+ DRM_INFO("%s: retire %d moves to inactive list %p\n",
+ __func__, request->seqno, obj);
+#endif
+
+ if (obj->write_domain != 0) {
+ list_move_tail(&obj_priv->list,
+ &dev_priv->mm.flushing_list);
+ } else {
+ i915_gem_object_move_to_inactive(obj);
+ }
+ }
+
+ if (request->flush_domains != 0) {
+ struct drm_i915_gem_object *obj_priv, *next;
+
+ /* Clear the write domain and activity from any buffers
+ * that are just waiting for a flush matching the one retired.
+ */
+ list_for_each_entry_safe(obj_priv, next,
+ &dev_priv->mm.flushing_list, list) {
+ struct drm_gem_object *obj = obj_priv->obj;
+
+ if (obj->write_domain & request->flush_domains) {
+ obj->write_domain = 0;
+ i915_gem_object_move_to_inactive(obj);
+ }
+ }
+
+ }
+}
+
+/**
+ * Returns true if seq1 is later than seq2.
+ */
+static int
+i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+{
+ return (int32_t)(seq1 - seq2) >= 0;
+}
+
+uint32_t
+i915_get_gem_seqno(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
+}
+
+/**
+ * This function clears the request list as sequence numbers are passed.
+ */
+void
+i915_gem_retire_requests(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ uint32_t seqno;
+
+ seqno = i915_get_gem_seqno(dev);
+
+ while (!list_empty(&dev_priv->mm.request_list)) {
+ struct drm_i915_gem_request *request;
+ uint32_t retiring_seqno;
+
+ request = list_first_entry(&dev_priv->mm.request_list,
+ struct drm_i915_gem_request,
+ list);
+ retiring_seqno = request->seqno;
+
+ if (i915_seqno_passed(seqno, retiring_seqno) ||
+ dev_priv->mm.wedged) {
+ i915_gem_retire_request(dev, request);
+
+ list_del(&request->list);
+ drm_free(request, sizeof(*request), DRM_MEM_DRIVER);
+ } else
+ break;
+ }
+}
+
+void
+i915_gem_retire_work_handler(struct work_struct *work)
+{
+ drm_i915_private_t *dev_priv;
+ struct drm_device *dev;
+
+ dev_priv = container_of(work, drm_i915_private_t,
+ mm.retire_work.work);
+ dev = dev_priv->dev;
+
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_retire_requests(dev);
+ if (!dev_priv->mm.suspended &&
+ !list_empty(&dev_priv->mm.request_list))
+ schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
+ mutex_unlock(&dev->struct_mutex);
+}
+
+/**
+ * Waits for a sequence number to be signaled, and cleans up the
+ * request and object lists appropriately for that event.
+ */
+static int
+i915_wait_request(struct drm_device *dev, uint32_t seqno)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret = 0;
+
+ BUG_ON(seqno == 0);
+
+ if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
+ dev_priv->mm.waiting_gem_seqno = seqno;
+ i915_user_irq_get(dev);
+ ret = wait_event_interruptible(dev_priv->irq_queue,
+ i915_seqno_passed(i915_get_gem_seqno(dev),
+ seqno) ||
+ dev_priv->mm.wedged);
+ i915_user_irq_put(dev);
+ dev_priv->mm.waiting_gem_seqno = 0;
+ }
+ if (dev_priv->mm.wedged)
+ ret = -EIO;
+
+ if (ret && ret != -ERESTARTSYS)
+ DRM_ERROR("%s returns %d (awaiting %d at %d)\n",
+ __func__, ret, seqno, i915_get_gem_seqno(dev));
+
+ /* Directly dispatch request retiring. While we have the work queue
+ * to handle this, the waiter on a request often wants an associated
+ * buffer to have made it to the inactive list, and we would need
+ * a separate wait queue to handle that.
+ */
+ if (ret == 0)
+ i915_gem_retire_requests(dev);
+
+ return ret;
+}
+
+static void
+i915_gem_flush(struct drm_device *dev,
+ uint32_t invalidate_domains,
+ uint32_t flush_domains)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ uint32_t cmd;
+ RING_LOCALS;
+
+#if WATCH_EXEC
+ DRM_INFO("%s: invalidate %08x flush %08x\n", __func__,
+ invalidate_domains, flush_domains);
+#endif
+
+ if (flush_domains & I915_GEM_DOMAIN_CPU)
+ drm_agp_chipset_flush(dev);
+
+ if ((invalidate_domains | flush_domains) & ~(I915_GEM_DOMAIN_CPU |
+ I915_GEM_DOMAIN_GTT)) {
+ /*
+ * read/write caches:
+ *
+ * I915_GEM_DOMAIN_RENDER is always invalidated, but is
+ * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is
+ * also flushed at 2d versus 3d pipeline switches.
+ *
+ * read-only caches:
+ *
+ * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
+ * MI_READ_FLUSH is set, and is always flushed on 965.
+ *
+ * I915_GEM_DOMAIN_COMMAND may not exist?
+ *
+ * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
+ * invalidated when MI_EXE_FLUSH is set.
+ *
+ * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
+ * invalidated with every MI_FLUSH.
+ *
+ * TLBs:
+ *
+ * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
+ * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
+ * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
+ * are flushed at any MI_FLUSH.
+ */
+
+ cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
+ if ((invalidate_domains|flush_domains) &
+ I915_GEM_DOMAIN_RENDER)
+ cmd &= ~MI_NO_WRITE_FLUSH;
+ if (!IS_I965G(dev)) {
+ /*
+ * On the 965, the sampler cache always gets flushed
+ * and this bit is reserved.
+ */
+ if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
+ cmd |= MI_READ_FLUSH;
+ }
+ if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
+ cmd |= MI_EXE_FLUSH;
+
+#if WATCH_EXEC
+ DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd);
+#endif
+ BEGIN_LP_RING(2);
+ OUT_RING(cmd);
+ OUT_RING(0); /* noop */
+ ADVANCE_LP_RING();
+ }
+}
+
+/**
+ * Ensures that all rendering to the object has completed and the object is
+ * safe to unbind from the GTT or access from the CPU.
+ */
+static int
+i915_gem_object_wait_rendering(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int ret;
+
+ /* If there are writes queued to the buffer, flush and
+ * create a new seqno to wait for.
+ */
+ if (obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) {
+ uint32_t write_domain = obj->write_domain;
+#if WATCH_BUF
+ DRM_INFO("%s: flushing object %p from write domain %08x\n",
+ __func__, obj, write_domain);
+#endif
+ i915_gem_flush(dev, 0, write_domain);
+
+ i915_gem_object_move_to_active(obj);
+ obj_priv->last_rendering_seqno = i915_add_request(dev,
+ write_domain);
+ BUG_ON(obj_priv->last_rendering_seqno == 0);
+#if WATCH_LRU
+ DRM_INFO("%s: flush moves to exec list %p\n", __func__, obj);
+#endif
+ }
+
+ /* If there is rendering queued on the buffer being evicted, wait for
+ * it.
+ */
+ if (obj_priv->active) {
+#if WATCH_BUF
+ DRM_INFO("%s: object %p wait for seqno %08x\n",
+ __func__, obj, obj_priv->last_rendering_seqno);
+#endif
+ ret = i915_wait_request(dev, obj_priv->last_rendering_seqno);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * Unbinds an object from the GTT aperture.
+ */
+static int
+i915_gem_object_unbind(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int ret = 0;
+
+#if WATCH_BUF
+ DRM_INFO("%s:%d %p\n", __func__, __LINE__, obj);
+ DRM_INFO("gtt_space %p\n", obj_priv->gtt_space);
+#endif
+ if (obj_priv->gtt_space == NULL)
+ return 0;
+
+ if (obj_priv->pin_count != 0) {
+ DRM_ERROR("Attempting to unbind pinned buffer\n");
+ return -EINVAL;
+ }
+
+ /* Wait for any rendering to complete
+ */
+ ret = i915_gem_object_wait_rendering(obj);
+ if (ret) {
+ DRM_ERROR("wait_rendering failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Move the object to the CPU domain to ensure that
+ * any possible CPU writes while it's not in the GTT
+ * are flushed when we go to remap it. This will
+ * also ensure that all pending GPU writes are finished
+ * before we unbind.
+ */
+ ret = i915_gem_object_set_domain(obj, I915_GEM_DOMAIN_CPU,
+ I915_GEM_DOMAIN_CPU);
+ if (ret) {
+ DRM_ERROR("set_domain failed: %d\n", ret);
+ return ret;
+ }
+
+ if (obj_priv->agp_mem != NULL) {
+ drm_unbind_agp(obj_priv->agp_mem);
+ drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
+ obj_priv->agp_mem = NULL;
+ }
+
+ BUG_ON(obj_priv->active);
+
+ i915_gem_object_free_page_list(obj);
+
+ if (obj_priv->gtt_space) {
+ atomic_dec(&dev->gtt_count);
+ atomic_sub(obj->size, &dev->gtt_memory);
+
+ drm_mm_put_block(obj_priv->gtt_space);
+ obj_priv->gtt_space = NULL;
+ }
+
+ /* Remove ourselves from the LRU list if present. */
+ if (!list_empty(&obj_priv->list))
+ list_del_init(&obj_priv->list);
+
+ return 0;
+}
+
+static int
+i915_gem_evict_something(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ int ret = 0;
+
+ for (;;) {
+ /* If there's an inactive buffer available now, grab it
+ * and be done.
+ */
+ if (!list_empty(&dev_priv->mm.inactive_list)) {
+ obj_priv = list_first_entry(&dev_priv->mm.inactive_list,
+ struct drm_i915_gem_object,
+ list);
+ obj = obj_priv->obj;
+ BUG_ON(obj_priv->pin_count != 0);
+#if WATCH_LRU
+ DRM_INFO("%s: evicting %p\n", __func__, obj);
+#endif
+ BUG_ON(obj_priv->active);
+
+ /* Wait on the rendering and unbind the buffer. */
+ ret = i915_gem_object_unbind(obj);
+ break;
+ }
+
+ /* If we didn't get anything, but the ring is still processing
+ * things, wait for one of those things to finish and hopefully
+ * leave us a buffer to evict.
+ */
+ if (!list_empty(&dev_priv->mm.request_list)) {
+ struct drm_i915_gem_request *request;
+
+ request = list_first_entry(&dev_priv->mm.request_list,
+ struct drm_i915_gem_request,
+ list);
+
+ ret = i915_wait_request(dev, request->seqno);
+ if (ret)
+ break;
+
+ /* if waiting caused an object to become inactive,
+ * then loop around and wait for it. Otherwise, we
+ * assume that waiting freed and unbound something,
+ * so there should now be some space in the GTT
+ */
+ if (!list_empty(&dev_priv->mm.inactive_list))
+ continue;
+ break;
+ }
+
+ /* If we didn't have anything on the request list but there
+ * are buffers awaiting a flush, emit one and try again.
+ * When we wait on it, those buffers waiting for that flush
+ * will get moved to inactive.
+ */
+ if (!list_empty(&dev_priv->mm.flushing_list)) {
+ obj_priv = list_first_entry(&dev_priv->mm.flushing_list,
+ struct drm_i915_gem_object,
+ list);
+ obj = obj_priv->obj;
+
+ i915_gem_flush(dev,
+ obj->write_domain,
+ obj->write_domain);
+ i915_add_request(dev, obj->write_domain);
+
+ obj = NULL;
+ continue;
+ }
+
+ DRM_ERROR("inactive empty %d request empty %d "
+ "flushing empty %d\n",
+ list_empty(&dev_priv->mm.inactive_list),
+ list_empty(&dev_priv->mm.request_list),
+ list_empty(&dev_priv->mm.flushing_list));
+ /* If we didn't do any of the above, there's nothing to be done
+ * and we just can't fit it in.
+ */
+ return -ENOMEM;
+ }
+ return ret;
+}
+
+static int
+i915_gem_object_get_page_list(struct drm_gem_object *obj)
+{
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int page_count, i;
+ struct address_space *mapping;
+ struct inode *inode;
+ struct page *page;
+ int ret;
+
+ if (obj_priv->page_list)
+ return 0;
+
+ /* Get the list of pages out of our struct file. They'll be pinned
+ * at this point until we release them.
+ */
+ page_count = obj->size / PAGE_SIZE;
+ BUG_ON(obj_priv->page_list != NULL);
+ obj_priv->page_list = drm_calloc(page_count, sizeof(struct page *),
+ DRM_MEM_DRIVER);
+ if (obj_priv->page_list == NULL) {
+ DRM_ERROR("Faled to allocate page list\n");
+ return -ENOMEM;
+ }
+
+ inode = obj->filp->f_path.dentry->d_inode;
+ mapping = inode->i_mapping;
+ for (i = 0; i < page_count; i++) {
+ page = read_mapping_page(mapping, i, NULL);
+ if (IS_ERR(page)) {
+ ret = PTR_ERR(page);
+ DRM_ERROR("read_mapping_page failed: %d\n", ret);
+ i915_gem_object_free_page_list(obj);
+ return ret;
+ }
+ obj_priv->page_list[i] = page;
+ }
+ return 0;
+}
+
+/**
+ * Finds free space in the GTT aperture and binds the object there.
+ */
+static int
+i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
+{
+ struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_mm_node *free_space;
+ int page_count, ret;
+
+ if (alignment == 0)
+ alignment = PAGE_SIZE;
+ if (alignment & (PAGE_SIZE - 1)) {
+ DRM_ERROR("Invalid object alignment requested %u\n", alignment);
+ return -EINVAL;
+ }
+
+ search_free:
+ free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
+ obj->size, alignment, 0);
+ if (free_space != NULL) {
+ obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size,
+ alignment);
+ if (obj_priv->gtt_space != NULL) {
+ obj_priv->gtt_space->private = obj;
+ obj_priv->gtt_offset = obj_priv->gtt_space->start;
+ }
+ }
+ if (obj_priv->gtt_space == NULL) {
+ /* If the gtt is empty and we're still having trouble
+ * fitting our object in, we're out of memory.
+ */
+#if WATCH_LRU
+ DRM_INFO("%s: GTT full, evicting something\n", __func__);
+#endif
+ if (list_empty(&dev_priv->mm.inactive_list) &&
+ list_empty(&dev_priv->mm.flushing_list) &&
+ list_empty(&dev_priv->mm.active_list)) {
+ DRM_ERROR("GTT full, but LRU list empty\n");
+ return -ENOMEM;
+ }
+
+ ret = i915_gem_evict_something(dev);
+ if (ret != 0) {
+ DRM_ERROR("Failed to evict a buffer %d\n", ret);
+ return ret;
+ }
+ goto search_free;
+ }
+
+#if WATCH_BUF
+ DRM_INFO("Binding object of size %d at 0x%08x\n",
+ obj->size, obj_priv->gtt_offset);
+#endif
+ ret = i915_gem_object_get_page_list(obj);
+ if (ret) {
+ drm_mm_put_block(obj_priv->gtt_space);
+ obj_priv->gtt_space = NULL;
+ return ret;
+ }
+
+ page_count = obj->size / PAGE_SIZE;
+ /* Create an AGP memory structure pointing at our pages, and bind it
+ * into the GTT.
+ */
+ obj_priv->agp_mem = drm_agp_bind_pages(dev,
+ obj_priv->page_list,
+ page_count,
+ obj_priv->gtt_offset,
+ obj_priv->agp_type);
+ if (obj_priv->agp_mem == NULL) {
+ i915_gem_object_free_page_list(obj);
+ drm_mm_put_block(obj_priv->gtt_space);
+ obj_priv->gtt_space = NULL;
+ return -ENOMEM;
+ }
+ atomic_inc(&dev->gtt_count);
+ atomic_add(obj->size, &dev->gtt_memory);
+
+ /* Assert that the object is not currently in any GPU domain. As it
+ * wasn't in the GTT, there shouldn't be any way it could have been in
+ * a GPU cache
+ */
+ BUG_ON(obj->read_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
+ BUG_ON(obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
+
+ return 0;
+}
+
+void
+i915_gem_clflush_object(struct drm_gem_object *obj)
+{
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ /* If we don't have a page list set up, then we're not pinned
+ * to GPU, and we can ignore the cache flush because it'll happen
+ * again at bind time.
+ */
+ if (obj_priv->page_list == NULL)
+ return;
+
+ drm_clflush_pages(obj_priv->page_list, obj->size / PAGE_SIZE);
+}
+
+/*
+ * Set the next domain for the specified object. This
+ * may not actually perform the necessary flushing/invaliding though,
+ * as that may want to be batched with other set_domain operations
+ *
+ * This is (we hope) the only really tricky part of gem. The goal
+ * is fairly simple -- track which caches hold bits of the object
+ * and make sure they remain coherent. A few concrete examples may
+ * help to explain how it works. For shorthand, we use the notation
+ * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the
+ * a pair of read and write domain masks.
+ *
+ * Case 1: the batch buffer
+ *
+ * 1. Allocated
+ * 2. Written by CPU
+ * 3. Mapped to GTT
+ * 4. Read by GPU
+ * 5. Unmapped from GTT
+ * 6. Freed
+ *
+ * Let's take these a step at a time
+ *
+ * 1. Allocated
+ * Pages allocated from the kernel may still have
+ * cache contents, so we set them to (CPU, CPU) always.
+ * 2. Written by CPU (using pwrite)
+ * The pwrite function calls set_domain (CPU, CPU) and
+ * this function does nothing (as nothing changes)
+ * 3. Mapped by GTT
+ * This function asserts that the object is not
+ * currently in any GPU-based read or write domains
+ * 4. Read by GPU
+ * i915_gem_execbuffer calls set_domain (COMMAND, 0).
+ * As write_domain is zero, this function adds in the
+ * current read domains (CPU+COMMAND, 0).
+ * flush_domains is set to CPU.
+ * invalidate_domains is set to COMMAND
+ * clflush is run to get data out of the CPU caches
+ * then i915_dev_set_domain calls i915_gem_flush to
+ * emit an MI_FLUSH and drm_agp_chipset_flush
+ * 5. Unmapped from GTT
+ * i915_gem_object_unbind calls set_domain (CPU, CPU)
+ * flush_domains and invalidate_domains end up both zero
+ * so no flushing/invalidating happens
+ * 6. Freed
+ * yay, done
+ *
+ * Case 2: The shared render buffer
+ *
+ * 1. Allocated
+ * 2. Mapped to GTT
+ * 3. Read/written by GPU
+ * 4. set_domain to (CPU,CPU)
+ * 5. Read/written by CPU
+ * 6. Read/written by GPU
+ *
+ * 1. Allocated
+ * Same as last example, (CPU, CPU)
+ * 2. Mapped to GTT
+ * Nothing changes (assertions find that it is not in the GPU)
+ * 3. Read/written by GPU
+ * execbuffer calls set_domain (RENDER, RENDER)
+ * flush_domains gets CPU
+ * invalidate_domains gets GPU
+ * clflush (obj)
+ * MI_FLUSH and drm_agp_chipset_flush
+ * 4. set_domain (CPU, CPU)
+ * flush_domains gets GPU
+ * invalidate_domains gets CPU
+ * wait_rendering (obj) to make sure all drawing is complete.
+ * This will include an MI_FLUSH to get the data from GPU
+ * to memory
+ * clflush (obj) to invalidate the CPU cache
+ * Another MI_FLUSH in i915_gem_flush (eliminate this somehow?)
+ * 5. Read/written by CPU
+ * cache lines are loaded and dirtied
+ * 6. Read written by GPU
+ * Same as last GPU access
+ *
+ * Case 3: The constant buffer
+ *
+ * 1. Allocated
+ * 2. Written by CPU
+ * 3. Read by GPU
+ * 4. Updated (written) by CPU again
+ * 5. Read by GPU
+ *
+ * 1. Allocated
+ * (CPU, CPU)
+ * 2. Written by CPU
+ * (CPU, CPU)
+ * 3. Read by GPU
+ * (CPU+RENDER, 0)
+ * flush_domains = CPU
+ * invalidate_domains = RENDER
+ * clflush (obj)
+ * MI_FLUSH
+ * drm_agp_chipset_flush
+ * 4. Updated (written) by CPU again
+ * (CPU, CPU)
+ * flush_domains = 0 (no previous write domain)
+ * invalidate_domains = 0 (no new read domains)
+ * 5. Read by GPU
+ * (CPU+RENDER, 0)
+ * flush_domains = CPU
+ * invalidate_domains = RENDER
+ * clflush (obj)
+ * MI_FLUSH
+ * drm_agp_chipset_flush
+ */
+static int
+i915_gem_object_set_domain(struct drm_gem_object *obj,
+ uint32_t read_domains,
+ uint32_t write_domain)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ uint32_t invalidate_domains = 0;
+ uint32_t flush_domains = 0;
+ int ret;
+
+#if WATCH_BUF
+ DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
+ __func__, obj,
+ obj->read_domains, read_domains,
+ obj->write_domain, write_domain);
+#endif
+ /*
+ * If the object isn't moving to a new write domain,
+ * let the object stay in multiple read domains
+ */
+ if (write_domain == 0)
+ read_domains |= obj->read_domains;
+ else
+ obj_priv->dirty = 1;
+
+ /*
+ * Flush the current write domain if
+ * the new read domains don't match. Invalidate
+ * any read domains which differ from the old
+ * write domain
+ */
+ if (obj->write_domain && obj->write_domain != read_domains) {
+ flush_domains |= obj->write_domain;
+ invalidate_domains |= read_domains & ~obj->write_domain;
+ }
+ /*
+ * Invalidate any read caches which may have
+ * stale data. That is, any new read domains.
+ */
+ invalidate_domains |= read_domains & ~obj->read_domains;
+ if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
+#if WATCH_BUF
+ DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
+ __func__, flush_domains, invalidate_domains);
+#endif
+ /*
+ * If we're invaliding the CPU cache and flushing a GPU cache,
+ * then pause for rendering so that the GPU caches will be
+ * flushed before the cpu cache is invalidated
+ */
+ if ((invalidate_domains & I915_GEM_DOMAIN_CPU) &&
+ (flush_domains & ~(I915_GEM_DOMAIN_CPU |
+ I915_GEM_DOMAIN_GTT))) {
+ ret = i915_gem_object_wait_rendering(obj);
+ if (ret)
+ return ret;
+ }
+ i915_gem_clflush_object(obj);
+ }
+
+ if ((write_domain | flush_domains) != 0)
+ obj->write_domain = write_domain;
+
+ /* If we're invalidating the CPU domain, clear the per-page CPU
+ * domain list as well.
+ */
+ if (obj_priv->page_cpu_valid != NULL &&
+ (write_domain != 0 ||
+ read_domains & I915_GEM_DOMAIN_CPU)) {
+ drm_free(obj_priv->page_cpu_valid, obj->size / PAGE_SIZE,
+ DRM_MEM_DRIVER);
+ obj_priv->page_cpu_valid = NULL;
+ }
+ obj->read_domains = read_domains;
+
+ dev->invalidate_domains |= invalidate_domains;
+ dev->flush_domains |= flush_domains;
+#if WATCH_BUF
+ DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n",
+ __func__,
+ obj->read_domains, obj->write_domain,
+ dev->invalidate_domains, dev->flush_domains);
+#endif
+ return 0;
+}
+
+/**
+ * Set the read/write domain on a range of the object.
+ *
+ * Currently only implemented for CPU reads, otherwise drops to normal
+ * i915_gem_object_set_domain().
+ */
+static int
+i915_gem_object_set_domain_range(struct drm_gem_object *obj,
+ uint64_t offset,
+ uint64_t size,
+ uint32_t read_domains,
+ uint32_t write_domain)
+{
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int ret, i;
+
+ if (obj->read_domains & I915_GEM_DOMAIN_CPU)
+ return 0;
+
+ if (read_domains != I915_GEM_DOMAIN_CPU ||
+ write_domain != 0)
+ return i915_gem_object_set_domain(obj,
+ read_domains, write_domain);
+
+ /* Wait on any GPU rendering to the object to be flushed. */
+ if (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) {
+ ret = i915_gem_object_wait_rendering(obj);
+ if (ret)
+ return ret;
+ }
+
+ if (obj_priv->page_cpu_valid == NULL) {
+ obj_priv->page_cpu_valid = drm_calloc(1, obj->size / PAGE_SIZE,
+ DRM_MEM_DRIVER);
+ }
+
+ /* Flush the cache on any pages that are still invalid from the CPU's
+ * perspective.
+ */
+ for (i = offset / PAGE_SIZE; i <= (offset + size - 1) / PAGE_SIZE; i++) {
+ if (obj_priv->page_cpu_valid[i])
+ continue;
+
+ drm_clflush_pages(obj_priv->page_list + i, 1);
+
+ obj_priv->page_cpu_valid[i] = 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Once all of the objects have been set in the proper domain,
+ * perform the necessary flush and invalidate operations.
+ *
+ * Returns the write domains flushed, for use in flush tracking.
+ */
+static uint32_t
+i915_gem_dev_set_domain(struct drm_device *dev)
+{
+ uint32_t flush_domains = dev->flush_domains;
+
+ /*
+ * Now that all the buffers are synced to the proper domains,
+ * flush and invalidate the collected domains
+ */
+ if (dev->invalidate_domains | dev->flush_domains) {
+#if WATCH_EXEC
+ DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
+ __func__,
+ dev->invalidate_domains,
+ dev->flush_domains);
+#endif
+ i915_gem_flush(dev,
+ dev->invalidate_domains,
+ dev->flush_domains);
+ dev->invalidate_domains = 0;
+ dev->flush_domains = 0;
+ }
+
+ return flush_domains;
+}
+
+/**
+ * Pin an object to the GTT and evaluate the relocations landing in it.
+ */
+static int
+i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
+ struct drm_file *file_priv,
+ struct drm_i915_gem_exec_object *entry)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_relocation_entry reloc;
+ struct drm_i915_gem_relocation_entry __user *relocs;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int i, ret;
+ uint32_t last_reloc_offset = -1;
+ void __iomem *reloc_page = NULL;
+
+ /* Choose the GTT offset for our buffer and put it there. */
+ ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment);
+ if (ret)
+ return ret;
+
+ entry->offset = obj_priv->gtt_offset;
+
+ relocs = (struct drm_i915_gem_relocation_entry __user *)
+ (uintptr_t) entry->relocs_ptr;
+ /* Apply the relocations, using the GTT aperture to avoid cache
+ * flushing requirements.
+ */
+ for (i = 0; i < entry->relocation_count; i++) {
+ struct drm_gem_object *target_obj;
+ struct drm_i915_gem_object *target_obj_priv;
+ uint32_t reloc_val, reloc_offset;
+ uint32_t __iomem *reloc_entry;
+
+ ret = copy_from_user(&reloc, relocs + i, sizeof(reloc));
+ if (ret != 0) {
+ i915_gem_object_unpin(obj);
+ return ret;
+ }
+
+ target_obj = drm_gem_object_lookup(obj->dev, file_priv,
+ reloc.target_handle);
+ if (target_obj == NULL) {
+ i915_gem_object_unpin(obj);
+ return -EBADF;
+ }
+ target_obj_priv = target_obj->driver_private;
+
+ /* The target buffer should have appeared before us in the
+ * exec_object list, so it should have a GTT space bound by now.
+ */
+ if (target_obj_priv->gtt_space == NULL) {
+ DRM_ERROR("No GTT space found for object %d\n",
+ reloc.target_handle);
+ drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
+ return -EINVAL;
+ }
+
+ if (reloc.offset > obj->size - 4) {
+ DRM_ERROR("Relocation beyond object bounds: "
+ "obj %p target %d offset %d size %d.\n",
+ obj, reloc.target_handle,
+ (int) reloc.offset, (int) obj->size);
+ drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
+ return -EINVAL;
+ }
+ if (reloc.offset & 3) {
+ DRM_ERROR("Relocation not 4-byte aligned: "
+ "obj %p target %d offset %d.\n",
+ obj, reloc.target_handle,
+ (int) reloc.offset);
+ drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
+ return -EINVAL;
+ }
+
+ if (reloc.write_domain && target_obj->pending_write_domain &&
+ reloc.write_domain != target_obj->pending_write_domain) {
+ DRM_ERROR("Write domain conflict: "
+ "obj %p target %d offset %d "
+ "new %08x old %08x\n",
+ obj, reloc.target_handle,
+ (int) reloc.offset,
+ reloc.write_domain,
+ target_obj->pending_write_domain);
+ drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
+ return -EINVAL;
+ }
+
+#if WATCH_RELOC
+ DRM_INFO("%s: obj %p offset %08x target %d "
+ "read %08x write %08x gtt %08x "
+ "presumed %08x delta %08x\n",
+ __func__,
+ obj,
+ (int) reloc.offset,
+ (int) reloc.target_handle,
+ (int) reloc.read_domains,
+ (int) reloc.write_domain,
+ (int) target_obj_priv->gtt_offset,
+ (int) reloc.presumed_offset,
+ reloc.delta);
+#endif
+
+ target_obj->pending_read_domains |= reloc.read_domains;
+ target_obj->pending_write_domain |= reloc.write_domain;
+
+ /* If the relocation already has the right value in it, no
+ * more work needs to be done.
+ */
+ if (target_obj_priv->gtt_offset == reloc.presumed_offset) {
+ drm_gem_object_unreference(target_obj);
+ continue;
+ }
+
+ /* Now that we're going to actually write some data in,
+ * make sure that any rendering using this buffer's contents
+ * is completed.
+ */
+ i915_gem_object_wait_rendering(obj);
+
+ /* As we're writing through the gtt, flush
+ * any CPU writes before we write the relocations
+ */
+ if (obj->write_domain & I915_GEM_DOMAIN_CPU) {
+ i915_gem_clflush_object(obj);
+ drm_agp_chipset_flush(dev);
+ obj->write_domain = 0;
+ }
+
+ /* Map the page containing the relocation we're going to
+ * perform.
+ */
+ reloc_offset = obj_priv->gtt_offset + reloc.offset;
+ if (reloc_page == NULL ||
+ (last_reloc_offset & ~(PAGE_SIZE - 1)) !=
+ (reloc_offset & ~(PAGE_SIZE - 1))) {
+ if (reloc_page != NULL)
+ iounmap(reloc_page);
+
+ reloc_page = ioremap_wc(dev->agp->base +
+ (reloc_offset &
+ ~(PAGE_SIZE - 1)),
+ PAGE_SIZE);
+ last_reloc_offset = reloc_offset;
+ if (reloc_page == NULL) {
+ drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
+ return -ENOMEM;
+ }
+ }
+
+ reloc_entry = (uint32_t __iomem *)(reloc_page +
+ (reloc_offset & (PAGE_SIZE - 1)));
+ reloc_val = target_obj_priv->gtt_offset + reloc.delta;
+
+#if WATCH_BUF
+ DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n",
+ obj, (unsigned int) reloc.offset,
+ readl(reloc_entry), reloc_val);
+#endif
+ writel(reloc_val, reloc_entry);
+
+ /* Write the updated presumed offset for this entry back out
+ * to the user.
+ */
+ reloc.presumed_offset = target_obj_priv->gtt_offset;
+ ret = copy_to_user(relocs + i, &reloc, sizeof(reloc));
+ if (ret != 0) {
+ drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
+ return ret;
+ }
+
+ drm_gem_object_unreference(target_obj);
+ }
+
+ if (reloc_page != NULL)
+ iounmap(reloc_page);
+
+#if WATCH_BUF
+ if (0)
+ i915_gem_dump_object(obj, 128, __func__, ~0);
+#endif
+ return 0;
+}
+
+/** Dispatch a batchbuffer to the ring
+ */
+static int
+i915_dispatch_gem_execbuffer(struct drm_device *dev,
+ struct drm_i915_gem_execbuffer *exec,
+ uint64_t exec_offset)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_clip_rect __user *boxes = (struct drm_clip_rect __user *)
+ (uintptr_t) exec->cliprects_ptr;
+ int nbox = exec->num_cliprects;
+ int i = 0, count;
+ uint32_t exec_start, exec_len;
+ RING_LOCALS;
+
+ exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+ exec_len = (uint32_t) exec->batch_len;
+
+ if ((exec_start | exec_len) & 0x7) {
+ DRM_ERROR("alignment\n");
+ return -EINVAL;
+ }
+
+ if (!exec_start)
+ return -EINVAL;
+
+ count = nbox ? nbox : 1;
+
+ for (i = 0; i < count; i++) {
+ if (i < nbox) {
+ int ret = i915_emit_box(dev, boxes, i,
+ exec->DR1, exec->DR4);
+ if (ret)
+ return ret;
+ }
+
+ if (IS_I830(dev) || IS_845G(dev)) {
+ BEGIN_LP_RING(4);
+ OUT_RING(MI_BATCH_BUFFER);
+ OUT_RING(exec_start | MI_BATCH_NON_SECURE);
+ OUT_RING(exec_start + exec_len - 4);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(2);
+ if (IS_I965G(dev)) {
+ OUT_RING(MI_BATCH_BUFFER_START |
+ (2 << 6) |
+ MI_BATCH_NON_SECURE_I965);
+ OUT_RING(exec_start);
+ } else {
+ OUT_RING(MI_BATCH_BUFFER_START |
+ (2 << 6));
+ OUT_RING(exec_start | MI_BATCH_NON_SECURE);
+ }
+ ADVANCE_LP_RING();
+ }
+ }
+
+ /* XXX breadcrumb */
+ return 0;
+}
+
+/* Throttle our rendering by waiting until the ring has completed our requests
+ * emitted over 20 msec ago.
+ *
+ * This should get us reasonable parallelism between CPU and GPU but also
+ * relatively low latency when blocking on a particular request to finish.
+ */
+static int
+i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
+{
+ struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+ int ret = 0;
+ uint32_t seqno;
+
+ mutex_lock(&dev->struct_mutex);
+ seqno = i915_file_priv->mm.last_gem_throttle_seqno;
+ i915_file_priv->mm.last_gem_throttle_seqno =
+ i915_file_priv->mm.last_gem_seqno;
+ if (seqno)
+ ret = i915_wait_request(dev, seqno);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+}
+
+int
+i915_gem_execbuffer(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+ struct drm_i915_gem_execbuffer *args = data;
+ struct drm_i915_gem_exec_object *exec_list = NULL;
+ struct drm_gem_object **object_list = NULL;
+ struct drm_gem_object *batch_obj;
+ int ret, i, pinned = 0;
+ uint64_t exec_offset;
+ uint32_t seqno, flush_domains;
+
+#if WATCH_EXEC
+ DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
+ (int) args->buffers_ptr, args->buffer_count, args->batch_len);
+#endif
+
+ if (args->buffer_count < 1) {
+ DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
+ return -EINVAL;
+ }
+ /* Copy in the exec list from userland */
+ exec_list = drm_calloc(sizeof(*exec_list), args->buffer_count,
+ DRM_MEM_DRIVER);
+ object_list = drm_calloc(sizeof(*object_list), args->buffer_count,
+ DRM_MEM_DRIVER);
+ if (exec_list == NULL || object_list == NULL) {
+ DRM_ERROR("Failed to allocate exec or object list "
+ "for %d buffers\n",
+ args->buffer_count);
+ ret = -ENOMEM;
+ goto pre_mutex_err;
+ }
+ ret = copy_from_user(exec_list,
+ (struct drm_i915_relocation_entry __user *)
+ (uintptr_t) args->buffers_ptr,
+ sizeof(*exec_list) * args->buffer_count);
+ if (ret != 0) {
+ DRM_ERROR("copy %d exec entries failed %d\n",
+ args->buffer_count, ret);
+ goto pre_mutex_err;
+ }
+
+ mutex_lock(&dev->struct_mutex);
+
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+
+ if (dev_priv->mm.wedged) {
+ DRM_ERROR("Execbuf while wedged\n");
+ mutex_unlock(&dev->struct_mutex);
+ return -EIO;
+ }
+
+ if (dev_priv->mm.suspended) {
+ DRM_ERROR("Execbuf while VT-switched.\n");
+ mutex_unlock(&dev->struct_mutex);
+ return -EBUSY;
+ }
+
+ /* Zero the gloabl flush/invalidate flags. These
+ * will be modified as each object is bound to the
+ * gtt
+ */
+ dev->invalidate_domains = 0;
+ dev->flush_domains = 0;
+
+ /* Look up object handles and perform the relocations */
+ for (i = 0; i < args->buffer_count; i++) {
+ object_list[i] = drm_gem_object_lookup(dev, file_priv,
+ exec_list[i].handle);
+ if (object_list[i] == NULL) {
+ DRM_ERROR("Invalid object handle %d at index %d\n",
+ exec_list[i].handle, i);
+ ret = -EBADF;
+ goto err;
+ }
+
+ object_list[i]->pending_read_domains = 0;
+ object_list[i]->pending_write_domain = 0;
+ ret = i915_gem_object_pin_and_relocate(object_list[i],
+ file_priv,
+ &exec_list[i]);
+ if (ret) {
+ DRM_ERROR("object bind and relocate failed %d\n", ret);
+ goto err;
+ }
+ pinned = i + 1;
+ }
+
+ /* Set the pending read domains for the batch buffer to COMMAND */
+ batch_obj = object_list[args->buffer_count-1];
+ batch_obj->pending_read_domains = I915_GEM_DOMAIN_COMMAND;
+ batch_obj->pending_write_domain = 0;
+
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+
+ for (i = 0; i < args->buffer_count; i++) {
+ struct drm_gem_object *obj = object_list[i];
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ if (obj_priv->gtt_space == NULL) {
+ /* We evicted the buffer in the process of validating
+ * our set of buffers in. We could try to recover by
+ * kicking them everything out and trying again from
+ * the start.
+ */
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* make sure all previous memory operations have passed */
+ ret = i915_gem_object_set_domain(obj,
+ obj->pending_read_domains,
+ obj->pending_write_domain);
+ if (ret)
+ goto err;
+ }
+
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+
+ /* Flush/invalidate caches and chipset buffer */
+ flush_domains = i915_gem_dev_set_domain(dev);
+
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+
+#if WATCH_COHERENCY
+ for (i = 0; i < args->buffer_count; i++) {
+ i915_gem_object_check_coherency(object_list[i],
+ exec_list[i].handle);
+ }
+#endif
+
+ exec_offset = exec_list[args->buffer_count - 1].offset;
+
+#if WATCH_EXEC
+ i915_gem_dump_object(object_list[args->buffer_count - 1],
+ args->batch_len,
+ __func__,
+ ~0);
+#endif
+
+ (void)i915_add_request(dev, flush_domains);
+
+ /* Exec the batchbuffer */
+ ret = i915_dispatch_gem_execbuffer(dev, args, exec_offset);
+ if (ret) {
+ DRM_ERROR("dispatch failed %d\n", ret);
+ goto err;
+ }
+
+ /*
+ * Ensure that the commands in the batch buffer are
+ * finished before the interrupt fires
+ */
+ flush_domains = i915_retire_commands(dev);
+
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+
+ /*
+ * Get a seqno representing the execution of the current buffer,
+ * which we can wait on. We would like to mitigate these interrupts,
+ * likely by only creating seqnos occasionally (so that we have
+ * *some* interrupts representing completion of buffers that we can
+ * wait on when trying to clear up gtt space).
+ */
+ seqno = i915_add_request(dev, flush_domains);
+ BUG_ON(seqno == 0);
+ i915_file_priv->mm.last_gem_seqno = seqno;
+ for (i = 0; i < args->buffer_count; i++) {
+ struct drm_gem_object *obj = object_list[i];
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ i915_gem_object_move_to_active(obj);
+ obj_priv->last_rendering_seqno = seqno;
+#if WATCH_LRU
+ DRM_INFO("%s: move to exec list %p\n", __func__, obj);
+#endif
+ }
+#if WATCH_LRU
+ i915_dump_lru(dev, __func__);
+#endif
+
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+
+ /* Copy the new buffer offsets back to the user's exec list. */
+ ret = copy_to_user((struct drm_i915_relocation_entry __user *)
+ (uintptr_t) args->buffers_ptr,
+ exec_list,
+ sizeof(*exec_list) * args->buffer_count);
+ if (ret)
+ DRM_ERROR("failed to copy %d exec entries "
+ "back to user (%d)\n",
+ args->buffer_count, ret);
+err:
+ if (object_list != NULL) {
+ for (i = 0; i < pinned; i++)
+ i915_gem_object_unpin(object_list[i]);
+
+ for (i = 0; i < args->buffer_count; i++)
+ drm_gem_object_unreference(object_list[i]);
+ }
+ mutex_unlock(&dev->struct_mutex);
+
+pre_mutex_err:
+ drm_free(object_list, sizeof(*object_list) * args->buffer_count,
+ DRM_MEM_DRIVER);
+ drm_free(exec_list, sizeof(*exec_list) * args->buffer_count,
+ DRM_MEM_DRIVER);
+
+ return ret;
+}
+
+int
+i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int ret;
+
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+ if (obj_priv->gtt_space == NULL) {
+ ret = i915_gem_object_bind_to_gtt(obj, alignment);
+ if (ret != 0) {
+ DRM_ERROR("Failure to bind: %d", ret);
+ return ret;
+ }
+ }
+ obj_priv->pin_count++;
+
+ /* If the object is not active and not pending a flush,
+ * remove it from the inactive list
+ */
+ if (obj_priv->pin_count == 1) {
+ atomic_inc(&dev->pin_count);
+ atomic_add(obj->size, &dev->pin_memory);
+ if (!obj_priv->active &&
+ (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
+ I915_GEM_DOMAIN_GTT)) == 0 &&
+ !list_empty(&obj_priv->list))
+ list_del_init(&obj_priv->list);
+ }
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+
+ return 0;
+}
+
+void
+i915_gem_object_unpin(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+ obj_priv->pin_count--;
+ BUG_ON(obj_priv->pin_count < 0);
+ BUG_ON(obj_priv->gtt_space == NULL);
+
+ /* If the object is no longer pinned, and is
+ * neither active nor being flushed, then stick it on
+ * the inactive list
+ */
+ if (obj_priv->pin_count == 0) {
+ if (!obj_priv->active &&
+ (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
+ I915_GEM_DOMAIN_GTT)) == 0)
+ list_move_tail(&obj_priv->list,
+ &dev_priv->mm.inactive_list);
+ atomic_dec(&dev->pin_count);
+ atomic_sub(obj->size, &dev->pin_memory);
+ }
+ i915_verify_inactive(dev, __FILE__, __LINE__);
+}
+
+int
+i915_gem_pin_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_pin *args = data;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ int ret;
+
+ mutex_lock(&dev->struct_mutex);
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL) {
+ DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n",
+ args->handle);
+ mutex_unlock(&dev->struct_mutex);
+ return -EBADF;
+ }
+ obj_priv = obj->driver_private;
+
+ ret = i915_gem_object_pin(obj, args->alignment);
+ if (ret != 0) {
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+
+ /* XXX - flush the CPU caches for pinned objects
+ * as the X server doesn't manage domains yet
+ */
+ if (obj->write_domain & I915_GEM_DOMAIN_CPU) {
+ i915_gem_clflush_object(obj);
+ drm_agp_chipset_flush(dev);
+ obj->write_domain = 0;
+ }
+ args->offset = obj_priv->gtt_offset;
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+int
+i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_pin *args = data;
+ struct drm_gem_object *obj;
+
+ mutex_lock(&dev->struct_mutex);
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL) {
+ DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n",
+ args->handle);
+ mutex_unlock(&dev->struct_mutex);
+ return -EBADF;
+ }
+
+ i915_gem_object_unpin(obj);
+
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ return 0;
+}
+
+int
+i915_gem_busy_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_busy *args = data;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL) {
+ DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
+ args->handle);
+ mutex_unlock(&dev->struct_mutex);
+ return -EBADF;
+ }
+
+ obj_priv = obj->driver_private;
+ args->busy = obj_priv->active;
+
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+ return 0;
+}
+
+int
+i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ return i915_gem_ring_throttle(dev, file_priv);
+}
+
+int i915_gem_init_object(struct drm_gem_object *obj)
+{
+ struct drm_i915_gem_object *obj_priv;
+
+ obj_priv = drm_calloc(1, sizeof(*obj_priv), DRM_MEM_DRIVER);
+ if (obj_priv == NULL)
+ return -ENOMEM;
+
+ /*
+ * We've just allocated pages from the kernel,
+ * so they've just been written by the CPU with
+ * zeros. They'll need to be clflushed before we
+ * use them with the GPU.
+ */
+ obj->write_domain = I915_GEM_DOMAIN_CPU;
+ obj->read_domains = I915_GEM_DOMAIN_CPU;
+
+ obj_priv->agp_type = AGP_USER_MEMORY;
+
+ obj->driver_private = obj_priv;
+ obj_priv->obj = obj;
+ INIT_LIST_HEAD(&obj_priv->list);
+ return 0;
+}
+
+void i915_gem_free_object(struct drm_gem_object *obj)
+{
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ while (obj_priv->pin_count > 0)
+ i915_gem_object_unpin(obj);
+
+ i915_gem_object_unbind(obj);
+
+ drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER);
+ drm_free(obj->driver_private, 1, DRM_MEM_DRIVER);
+}
+
+static int
+i915_gem_set_domain(struct drm_gem_object *obj,
+ struct drm_file *file_priv,
+ uint32_t read_domains,
+ uint32_t write_domain)
+{
+ struct drm_device *dev = obj->dev;
+ int ret;
+ uint32_t flush_domains;
+
+ BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+
+ ret = i915_gem_object_set_domain(obj, read_domains, write_domain);
+ if (ret)
+ return ret;
+ flush_domains = i915_gem_dev_set_domain(obj->dev);
+
+ if (flush_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT))
+ (void) i915_add_request(dev, flush_domains);
+
+ return 0;
+}
+
+/** Unbinds all objects that are on the given buffer list. */
+static int
+i915_gem_evict_from_list(struct drm_device *dev, struct list_head *head)
+{
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ int ret;
+
+ while (!list_empty(head)) {
+ obj_priv = list_first_entry(head,
+ struct drm_i915_gem_object,
+ list);
+ obj = obj_priv->obj;
+
+ if (obj_priv->pin_count != 0) {
+ DRM_ERROR("Pinned object in unbind list\n");
+ mutex_unlock(&dev->struct_mutex);
+ return -EINVAL;
+ }
+
+ ret = i915_gem_object_unbind(obj);
+ if (ret != 0) {
+ DRM_ERROR("Error unbinding object in LeaveVT: %d\n",
+ ret);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+ }
+
+
+ return 0;
+}
+
+static int
+i915_gem_idle(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ uint32_t seqno, cur_seqno, last_seqno;
+ int stuck, ret;
+
+ mutex_lock(&dev->struct_mutex);
+
+ if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) {
+ mutex_unlock(&dev->struct_mutex);
+ return 0;
+ }
+
+ /* Hack! Don't let anybody do execbuf while we don't control the chip.
+ * We need to replace this with a semaphore, or something.
+ */
+ dev_priv->mm.suspended = 1;
+
+ /* Cancel the retire work handler, wait for it to finish if running
+ */
+ mutex_unlock(&dev->struct_mutex);
+ cancel_delayed_work_sync(&dev_priv->mm.retire_work);
+ mutex_lock(&dev->struct_mutex);
+
+ i915_kernel_lost_context(dev);
+
+ /* Flush the GPU along with all non-CPU write domains
+ */
+ i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT),
+ ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
+ seqno = i915_add_request(dev, ~(I915_GEM_DOMAIN_CPU |
+ I915_GEM_DOMAIN_GTT));
+
+ if (seqno == 0) {
+ mutex_unlock(&dev->struct_mutex);
+ return -ENOMEM;
+ }
+
+ dev_priv->mm.waiting_gem_seqno = seqno;
+ last_seqno = 0;
+ stuck = 0;
+ for (;;) {
+ cur_seqno = i915_get_gem_seqno(dev);
+ if (i915_seqno_passed(cur_seqno, seqno))
+ break;
+ if (last_seqno == cur_seqno) {
+ if (stuck++ > 100) {
+ DRM_ERROR("hardware wedged\n");
+ dev_priv->mm.wedged = 1;
+ DRM_WAKEUP(&dev_priv->irq_queue);
+ break;
+ }
+ }
+ msleep(10);
+ last_seqno = cur_seqno;
+ }
+ dev_priv->mm.waiting_gem_seqno = 0;
+
+ i915_gem_retire_requests(dev);
+
+ /* Active and flushing should now be empty as we've
+ * waited for a sequence higher than any pending execbuffer
+ */
+ BUG_ON(!list_empty(&dev_priv->mm.active_list));
+ BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+
+ /* Request should now be empty as we've also waited
+ * for the last request in the list
+ */
+ BUG_ON(!list_empty(&dev_priv->mm.request_list));
+
+ /* Move all buffers out of the GTT. */
+ ret = i915_gem_evict_from_list(dev, &dev_priv->mm.inactive_list);
+ if (ret) {
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+
+ BUG_ON(!list_empty(&dev_priv->mm.active_list));
+ BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+ BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
+ BUG_ON(!list_empty(&dev_priv->mm.request_list));
+
+ i915_gem_cleanup_ringbuffer(dev);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+static int
+i915_gem_init_hws(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ int ret;
+
+ /* If we need a physical address for the status page, it's already
+ * initialized at driver load time.
+ */
+ if (!I915_NEED_GFX_HWS(dev))
+ return 0;
+
+ obj = drm_gem_object_alloc(dev, 4096);
+ if (obj == NULL) {
+ DRM_ERROR("Failed to allocate status page\n");
+ return -ENOMEM;
+ }
+ obj_priv = obj->driver_private;
+ obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
+
+ ret = i915_gem_object_pin(obj, 4096);
+ if (ret != 0) {
+ drm_gem_object_unreference(obj);
+ return ret;
+ }
+
+ dev_priv->status_gfx_addr = obj_priv->gtt_offset;
+
+ dev_priv->hw_status_page = kmap(obj_priv->page_list[0]);
+ if (dev_priv->hw_status_page == NULL) {
+ DRM_ERROR("Failed to map status page.\n");
+ memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
+ drm_gem_object_unreference(obj);
+ return -EINVAL;
+ }
+ dev_priv->hws_obj = obj;
+ memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+ I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
+ I915_READ(HWS_PGA); /* posting read */
+ DRM_DEBUG("hws offset: 0x%08x\n", dev_priv->status_gfx_addr);
+
+ return 0;
+}
+
+static int
+i915_gem_init_ringbuffer(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ int ret;
+ u32 head;
+
+ ret = i915_gem_init_hws(dev);
+ if (ret != 0)
+ return ret;
+
+ obj = drm_gem_object_alloc(dev, 128 * 1024);
+ if (obj == NULL) {
+ DRM_ERROR("Failed to allocate ringbuffer\n");
+ return -ENOMEM;
+ }
+ obj_priv = obj->driver_private;
+
+ ret = i915_gem_object_pin(obj, 4096);
+ if (ret != 0) {
+ drm_gem_object_unreference(obj);
+ return ret;
+ }
+
+ /* Set up the kernel mapping for the ring. */
+ dev_priv->ring.Size = obj->size;
+ dev_priv->ring.tail_mask = obj->size - 1;
+
+ dev_priv->ring.map.offset = dev->agp->base + obj_priv->gtt_offset;
+ dev_priv->ring.map.size = obj->size;
+ dev_priv->ring.map.type = 0;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
+
+ drm_core_ioremap_wc(&dev_priv->ring.map, dev);
+ if (dev_priv->ring.map.handle == NULL) {
+ DRM_ERROR("Failed to map ringbuffer.\n");
+ memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
+ drm_gem_object_unreference(obj);
+ return -EINVAL;
+ }
+ dev_priv->ring.ring_obj = obj;
+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
+ /* Stop the ring if it's running. */
+ I915_WRITE(PRB0_CTL, 0);
+ I915_WRITE(PRB0_TAIL, 0);
+ I915_WRITE(PRB0_HEAD, 0);
+
+ /* Initialize the ring. */
+ I915_WRITE(PRB0_START, obj_priv->gtt_offset);
+ head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+
+ /* G45 ring initialization fails to reset head to zero */
+ if (head != 0) {
+ DRM_ERROR("Ring head not reset to zero "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ I915_READ(PRB0_CTL),
+ I915_READ(PRB0_HEAD),
+ I915_READ(PRB0_TAIL),
+ I915_READ(PRB0_START));
+ I915_WRITE(PRB0_HEAD, 0);
+
+ DRM_ERROR("Ring head forced to zero "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ I915_READ(PRB0_CTL),
+ I915_READ(PRB0_HEAD),
+ I915_READ(PRB0_TAIL),
+ I915_READ(PRB0_START));
+ }
+
+ I915_WRITE(PRB0_CTL,
+ ((obj->size - 4096) & RING_NR_PAGES) |
+ RING_NO_REPORT |
+ RING_VALID);
+
+ head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+
+ /* If the head is still not zero, the ring is dead */
+ if (head != 0) {
+ DRM_ERROR("Ring initialization failed "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ I915_READ(PRB0_CTL),
+ I915_READ(PRB0_HEAD),
+ I915_READ(PRB0_TAIL),
+ I915_READ(PRB0_START));
+ return -EIO;
+ }
+
+ /* Update our cache of the ring state */
+ i915_kernel_lost_context(dev);
+
+ return 0;
+}
+
+static void
+i915_gem_cleanup_ringbuffer(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (dev_priv->ring.ring_obj == NULL)
+ return;
+
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
+
+ i915_gem_object_unpin(dev_priv->ring.ring_obj);
+ drm_gem_object_unreference(dev_priv->ring.ring_obj);
+ dev_priv->ring.ring_obj = NULL;
+ memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
+
+ if (dev_priv->hws_obj != NULL) {
+ struct drm_gem_object *obj = dev_priv->hws_obj;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ kunmap(obj_priv->page_list[0]);
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(obj);
+ dev_priv->hws_obj = NULL;
+ memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
+ dev_priv->hw_status_page = NULL;
+
+ /* Write high address into HWS_PGA when disabling. */
+ I915_WRITE(HWS_PGA, 0x1ffff000);
+ }
+}
+
+int
+i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
+
+ if (dev_priv->mm.wedged) {
+ DRM_ERROR("Reenabling wedged hardware, good luck\n");
+ dev_priv->mm.wedged = 0;
+ }
+
+ ret = i915_gem_init_ringbuffer(dev);
+ if (ret != 0)
+ return ret;
+
+ mutex_lock(&dev->struct_mutex);
+ BUG_ON(!list_empty(&dev_priv->mm.active_list));
+ BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+ BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
+ BUG_ON(!list_empty(&dev_priv->mm.request_list));
+ dev_priv->mm.suspended = 0;
+ mutex_unlock(&dev->struct_mutex);
+
+ drm_irq_install(dev);
+
+ return 0;
+}
+
+int
+i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ int ret;
+
+ ret = i915_gem_idle(dev);
+ drm_irq_uninstall(dev);
+
+ return ret;
+}
+
+void
+i915_gem_lastclose(struct drm_device *dev)
+{
+ int ret;
+
+ ret = i915_gem_idle(dev);
+ if (ret)
+ DRM_ERROR("failed to idle hardware: %d\n", ret);
+}
+
+void
+i915_gem_load(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ INIT_LIST_HEAD(&dev_priv->mm.active_list);
+ INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
+ INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+ INIT_LIST_HEAD(&dev_priv->mm.request_list);
+ INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
+ i915_gem_retire_work_handler);
+ dev_priv->mm.next_gem_seqno = 1;
+
+ i915_gem_detect_bit_6_swizzle(dev);
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c
new file mode 100644
index 00000000000..131c088f8c8
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_debug.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Packard <keithp@keithp.com>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#if WATCH_INACTIVE
+void
+i915_verify_inactive(struct drm_device *dev, char *file, int line)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+
+ list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+ obj = obj_priv->obj;
+ if (obj_priv->pin_count || obj_priv->active ||
+ (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
+ I915_GEM_DOMAIN_GTT)))
+ DRM_ERROR("inactive %p (p %d a %d w %x) %s:%d\n",
+ obj,
+ obj_priv->pin_count, obj_priv->active,
+ obj->write_domain, file, line);
+ }
+}
+#endif /* WATCH_INACTIVE */
+
+
+#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE
+static void
+i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
+ uint32_t bias, uint32_t mark)
+{
+ uint32_t *mem = kmap_atomic(page, KM_USER0);
+ int i;
+ for (i = start; i < end; i += 4)
+ DRM_INFO("%08x: %08x%s\n",
+ (int) (bias + i), mem[i / 4],
+ (bias + i == mark) ? " ********" : "");
+ kunmap_atomic(mem, KM_USER0);
+ /* give syslog time to catch up */
+ msleep(1);
+}
+
+void
+i915_gem_dump_object(struct drm_gem_object *obj, int len,
+ const char *where, uint32_t mark)
+{
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int page;
+
+ DRM_INFO("%s: object at offset %08x\n", where, obj_priv->gtt_offset);
+ for (page = 0; page < (len + PAGE_SIZE-1) / PAGE_SIZE; page++) {
+ int page_len, chunk, chunk_len;
+
+ page_len = len - page * PAGE_SIZE;
+ if (page_len > PAGE_SIZE)
+ page_len = PAGE_SIZE;
+
+ for (chunk = 0; chunk < page_len; chunk += 128) {
+ chunk_len = page_len - chunk;
+ if (chunk_len > 128)
+ chunk_len = 128;
+ i915_gem_dump_page(obj_priv->page_list[page],
+ chunk, chunk + chunk_len,
+ obj_priv->gtt_offset +
+ page * PAGE_SIZE,
+ mark);
+ }
+ }
+}
+#endif
+
+#if WATCH_LRU
+void
+i915_dump_lru(struct drm_device *dev, const char *where)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv;
+
+ DRM_INFO("active list %s {\n", where);
+ list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
+ list)
+ {
+ DRM_INFO(" %p: %08x\n", obj_priv,
+ obj_priv->last_rendering_seqno);
+ }
+ DRM_INFO("}\n");
+ DRM_INFO("flushing list %s {\n", where);
+ list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
+ list)
+ {
+ DRM_INFO(" %p: %08x\n", obj_priv,
+ obj_priv->last_rendering_seqno);
+ }
+ DRM_INFO("}\n");
+ DRM_INFO("inactive %s {\n", where);
+ list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+ DRM_INFO(" %p: %08x\n", obj_priv,
+ obj_priv->last_rendering_seqno);
+ }
+ DRM_INFO("}\n");
+}
+#endif
+
+
+#if WATCH_COHERENCY
+void
+i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int page;
+ uint32_t *gtt_mapping;
+ uint32_t *backing_map = NULL;
+ int bad_count = 0;
+
+ DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %dkb):\n",
+ __func__, obj, obj_priv->gtt_offset, handle,
+ obj->size / 1024);
+
+ gtt_mapping = ioremap(dev->agp->base + obj_priv->gtt_offset,
+ obj->size);
+ if (gtt_mapping == NULL) {
+ DRM_ERROR("failed to map GTT space\n");
+ return;
+ }
+
+ for (page = 0; page < obj->size / PAGE_SIZE; page++) {
+ int i;
+
+ backing_map = kmap_atomic(obj_priv->page_list[page], KM_USER0);
+
+ if (backing_map == NULL) {
+ DRM_ERROR("failed to map backing page\n");
+ goto out;
+ }
+
+ for (i = 0; i < PAGE_SIZE / 4; i++) {
+ uint32_t cpuval = backing_map[i];
+ uint32_t gttval = readl(gtt_mapping +
+ page * 1024 + i);
+
+ if (cpuval != gttval) {
+ DRM_INFO("incoherent CPU vs GPU at 0x%08x: "
+ "0x%08x vs 0x%08x\n",
+ (int)(obj_priv->gtt_offset +
+ page * PAGE_SIZE + i * 4),
+ cpuval, gttval);
+ if (bad_count++ >= 8) {
+ DRM_INFO("...\n");
+ goto out;
+ }
+ }
+ }
+ kunmap_atomic(backing_map, KM_USER0);
+ backing_map = NULL;
+ }
+
+ out:
+ if (backing_map != NULL)
+ kunmap_atomic(backing_map, KM_USER0);
+ iounmap(gtt_mapping);
+
+ /* give syslog time to catch up */
+ msleep(1);
+
+ /* Directly flush the object, since we just loaded values with the CPU
+ * from the backing pages and we don't want to disturb the cache
+ * management that we're trying to observe.
+ */
+
+ i915_gem_clflush_object(obj);
+}
+#endif
diff --git a/drivers/gpu/drm/i915/i915_gem_proc.c b/drivers/gpu/drm/i915/i915_gem_proc.c
new file mode 100644
index 00000000000..93de15b4c9a
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_proc.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Keith Packard <keithp@keithp.com>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+static int i915_gem_active_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+ DRM_PROC_PRINT("Active:\n");
+ list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
+ list)
+ {
+ struct drm_gem_object *obj = obj_priv->obj;
+ if (obj->name) {
+ DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
+ obj, obj->name,
+ obj->read_domains, obj->write_domain,
+ obj_priv->last_rendering_seqno);
+ } else {
+ DRM_PROC_PRINT(" %p: %08x %08x %d\n",
+ obj,
+ obj->read_domains, obj->write_domain,
+ obj_priv->last_rendering_seqno);
+ }
+ }
+ if (len > request + offset)
+ return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int i915_gem_flushing_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+ DRM_PROC_PRINT("Flushing:\n");
+ list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
+ list)
+ {
+ struct drm_gem_object *obj = obj_priv->obj;
+ if (obj->name) {
+ DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
+ obj, obj->name,
+ obj->read_domains, obj->write_domain,
+ obj_priv->last_rendering_seqno);
+ } else {
+ DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj,
+ obj->read_domains, obj->write_domain,
+ obj_priv->last_rendering_seqno);
+ }
+ }
+ if (len > request + offset)
+ return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int i915_gem_inactive_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+ DRM_PROC_PRINT("Inactive:\n");
+ list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list,
+ list)
+ {
+ struct drm_gem_object *obj = obj_priv->obj;
+ if (obj->name) {
+ DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
+ obj, obj->name,
+ obj->read_domains, obj->write_domain,
+ obj_priv->last_rendering_seqno);
+ } else {
+ DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj,
+ obj->read_domains, obj->write_domain,
+ obj_priv->last_rendering_seqno);
+ }
+ }
+ if (len > request + offset)
+ return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int i915_gem_request_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_request *gem_request;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+ DRM_PROC_PRINT("Request:\n");
+ list_for_each_entry(gem_request, &dev_priv->mm.request_list,
+ list)
+ {
+ DRM_PROC_PRINT(" %d @ %d %08x\n",
+ gem_request->seqno,
+ (int) (jiffies - gem_request->emitted_jiffies),
+ gem_request->flush_domains);
+ }
+ if (len > request + offset)
+ return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static int i915_gem_seqno_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+ if (dev_priv->hw_status_page != NULL) {
+ DRM_PROC_PRINT("Current sequence: %d\n",
+ i915_get_gem_seqno(dev));
+ } else {
+ DRM_PROC_PRINT("Current sequence: hws uninitialized\n");
+ }
+ DRM_PROC_PRINT("Waiter sequence: %d\n",
+ dev_priv->mm.waiting_gem_seqno);
+ DRM_PROC_PRINT("IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno);
+ if (len > request + offset)
+ return request;
+ *eof = 1;
+ return len - offset;
+}
+
+
+static int i915_interrupt_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+ DRM_PROC_PRINT("Interrupt enable: %08x\n",
+ I915_READ(IER));
+ DRM_PROC_PRINT("Interrupt identity: %08x\n",
+ I915_READ(IIR));
+ DRM_PROC_PRINT("Interrupt mask: %08x\n",
+ I915_READ(IMR));
+ DRM_PROC_PRINT("Pipe A stat: %08x\n",
+ I915_READ(PIPEASTAT));
+ DRM_PROC_PRINT("Pipe B stat: %08x\n",
+ I915_READ(PIPEBSTAT));
+ DRM_PROC_PRINT("Interrupts received: %d\n",
+ atomic_read(&dev_priv->irq_received));
+ if (dev_priv->hw_status_page != NULL) {
+ DRM_PROC_PRINT("Current sequence: %d\n",
+ i915_get_gem_seqno(dev));
+ } else {
+ DRM_PROC_PRINT("Current sequence: hws uninitialized\n");
+ }
+ DRM_PROC_PRINT("Waiter sequence: %d\n",
+ dev_priv->mm.waiting_gem_seqno);
+ DRM_PROC_PRINT("IRQ sequence: %d\n",
+ dev_priv->mm.irq_gem_seqno);
+ if (len > request + offset)
+ return request;
+ *eof = 1;
+ return len - offset;
+}
+
+static struct drm_proc_list {
+ /** file name */
+ const char *name;
+ /** proc callback*/
+ int (*f) (char *, char **, off_t, int, int *, void *);
+} i915_gem_proc_list[] = {
+ {"i915_gem_active", i915_gem_active_info},
+ {"i915_gem_flushing", i915_gem_flushing_info},
+ {"i915_gem_inactive", i915_gem_inactive_info},
+ {"i915_gem_request", i915_gem_request_info},
+ {"i915_gem_seqno", i915_gem_seqno_info},
+ {"i915_gem_interrupt", i915_interrupt_info},
+};
+
+#define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
+
+int i915_gem_proc_init(struct drm_minor *minor)
+{
+ struct proc_dir_entry *ent;
+ int i, j;
+
+ for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) {
+ ent = create_proc_entry(i915_gem_proc_list[i].name,
+ S_IFREG | S_IRUGO, minor->dev_root);
+ if (!ent) {
+ DRM_ERROR("Cannot create /proc/dri/.../%s\n",
+ i915_gem_proc_list[i].name);
+ for (j = 0; j < i; j++)
+ remove_proc_entry(i915_gem_proc_list[i].name,
+ minor->dev_root);
+ return -1;
+ }
+ ent->read_proc = i915_gem_proc_list[i].f;
+ ent->data = minor;
+ }
+ return 0;
+}
+
+void i915_gem_proc_cleanup(struct drm_minor *minor)
+{
+ int i;
+
+ if (!minor->dev_root)
+ return;
+
+ for (i = 0; i < I915_GEM_PROC_ENTRIES; i++)
+ remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root);
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
new file mode 100644
index 00000000000..e8b85ac4ca0
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/** @file i915_gem_tiling.c
+ *
+ * Support for managing tiling state of buffer objects.
+ *
+ * The idea behind tiling is to increase cache hit rates by rearranging
+ * pixel data so that a group of pixel accesses are in the same cacheline.
+ * Performance improvement from doing this on the back/depth buffer are on
+ * the order of 30%.
+ *
+ * Intel architectures make this somewhat more complicated, though, by
+ * adjustments made to addressing of data when the memory is in interleaved
+ * mode (matched pairs of DIMMS) to improve memory bandwidth.
+ * For interleaved memory, the CPU sends every sequential 64 bytes
+ * to an alternate memory channel so it can get the bandwidth from both.
+ *
+ * The GPU also rearranges its accesses for increased bandwidth to interleaved
+ * memory, and it matches what the CPU does for non-tiled. However, when tiled
+ * it does it a little differently, since one walks addresses not just in the
+ * X direction but also Y. So, along with alternating channels when bit
+ * 6 of the address flips, it also alternates when other bits flip -- Bits 9
+ * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
+ * are common to both the 915 and 965-class hardware.
+ *
+ * The CPU also sometimes XORs in higher bits as well, to improve
+ * bandwidth doing strided access like we do so frequently in graphics. This
+ * is called "Channel XOR Randomization" in the MCH documentation. The result
+ * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
+ * decode.
+ *
+ * All of this bit 6 XORing has an effect on our memory management,
+ * as we need to make sure that the 3d driver can correctly address object
+ * contents.
+ *
+ * If we don't have interleaved memory, all tiling is safe and no swizzling is
+ * required.
+ *
+ * When bit 17 is XORed in, we simply refuse to tile at all. Bit
+ * 17 is not just a page offset, so as we page an objet out and back in,
+ * individual pages in it will have different bit 17 addresses, resulting in
+ * each 64 bytes being swapped with its neighbor!
+ *
+ * Otherwise, if interleaved, we have to tell the 3d driver what the address
+ * swizzling it needs to do is, since it's writing with the CPU to the pages
+ * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
+ * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
+ * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
+ * to match what the GPU expects.
+ */
+
+/**
+ * Detects bit 6 swizzling of address lookup between IGD access and CPU
+ * access through main memory.
+ */
+void
+i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+ uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+
+ if (!IS_I9XX(dev)) {
+ /* As far as we know, the 865 doesn't have these bit 6
+ * swizzling issues.
+ */
+ swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+ swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+ } else if ((!IS_I965G(dev) && !IS_G33(dev)) || IS_I965GM(dev) ||
+ IS_GM45(dev)) {
+ uint32_t dcc;
+
+ /* On 915-945 and GM965, channel interleave by the CPU is
+ * determined by DCC. The CPU will alternate based on bit 6
+ * in interleaved mode, and the GPU will then also alternate
+ * on bit 6, 9, and 10 for X, but the CPU may also optionally
+ * alternate based on bit 17 (XOR not disabled and XOR
+ * bit == 17).
+ */
+ dcc = I915_READ(DCC);
+ switch (dcc & DCC_ADDRESSING_MODE_MASK) {
+ case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
+ case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
+ swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+ swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+ break;
+ case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
+ if (IS_I915G(dev) || IS_I915GM(dev) ||
+ dcc & DCC_CHANNEL_XOR_DISABLE) {
+ swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+ swizzle_y = I915_BIT_6_SWIZZLE_9;
+ } else if (IS_I965GM(dev) || IS_GM45(dev)) {
+ /* GM965 only does bit 11-based channel
+ * randomization
+ */
+ swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
+ swizzle_y = I915_BIT_6_SWIZZLE_9_11;
+ } else {
+ /* Bit 17 or perhaps other swizzling */
+ swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+ swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+ }
+ break;
+ }
+ if (dcc == 0xffffffff) {
+ DRM_ERROR("Couldn't read from MCHBAR. "
+ "Disabling tiling.\n");
+ swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+ swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+ }
+ } else {
+ /* The 965, G33, and newer, have a very flexible memory
+ * configuration. It will enable dual-channel mode
+ * (interleaving) on as much memory as it can, and the GPU
+ * will additionally sometimes enable different bit 6
+ * swizzling for tiled objects from the CPU.
+ *
+ * Here's what I found on the G965:
+ * slot fill memory size swizzling
+ * 0A 0B 1A 1B 1-ch 2-ch
+ * 512 0 0 0 512 0 O
+ * 512 0 512 0 16 1008 X
+ * 512 0 0 512 16 1008 X
+ * 0 512 0 512 16 1008 X
+ * 1024 1024 1024 0 2048 1024 O
+ *
+ * We could probably detect this based on either the DRB
+ * matching, which was the case for the swizzling required in
+ * the table above, or from the 1-ch value being less than
+ * the minimum size of a rank.
+ */
+ if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
+ swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+ swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+ } else {
+ swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+ swizzle_y = I915_BIT_6_SWIZZLE_9;
+ }
+ }
+
+ dev_priv->mm.bit_6_swizzle_x = swizzle_x;
+ dev_priv->mm.bit_6_swizzle_y = swizzle_y;
+}
+
+/**
+ * Sets the tiling mode of an object, returning the required swizzling of
+ * bit 6 of addresses in the object.
+ */
+int
+i915_gem_set_tiling(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_set_tiling *args = data;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL)
+ return -EINVAL;
+ obj_priv = obj->driver_private;
+
+ mutex_lock(&dev->struct_mutex);
+
+ if (args->tiling_mode == I915_TILING_NONE) {
+ obj_priv->tiling_mode = I915_TILING_NONE;
+ args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+ } else {
+ if (args->tiling_mode == I915_TILING_X)
+ args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
+ else
+ args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
+ /* If we can't handle the swizzling, make it untiled. */
+ if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
+ args->tiling_mode = I915_TILING_NONE;
+ args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+ }
+ }
+ obj_priv->tiling_mode = args->tiling_mode;
+
+ mutex_unlock(&dev->struct_mutex);
+
+ drm_gem_object_unreference(obj);
+
+ return 0;
+}
+
+/**
+ * Returns the current tiling mode and required bit 6 swizzling for the object.
+ */
+int
+i915_gem_get_tiling(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_get_tiling *args = data;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL)
+ return -EINVAL;
+ obj_priv = obj->driver_private;
+
+ mutex_lock(&dev->struct_mutex);
+
+ args->tiling_mode = obj_priv->tiling_mode;
+ switch (obj_priv->tiling_mode) {
+ case I915_TILING_X:
+ args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
+ break;
+ case I915_TILING_Y:
+ args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
+ break;
+ case I915_TILING_NONE:
+ args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+ break;
+ default:
+ DRM_ERROR("unknown tiling mode\n");
+ }
+
+ mutex_unlock(&dev->struct_mutex);
+
+ drm_gem_object_unreference(obj);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index df036118b8b..26f48932a51 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -31,16 +31,62 @@
#include "i915_drm.h"
#include "i915_drv.h"
-#define USER_INT_FLAG (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
-
#define MAX_NOPID ((u32)~0)
+/** These are the interrupts used by the driver */
+#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \
+ I915_ASLE_INTERRUPT | \
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
+
+void
+i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+ if ((dev_priv->irq_mask_reg & mask) != 0) {
+ dev_priv->irq_mask_reg &= ~mask;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
+}
+
+static inline void
+i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+ if ((dev_priv->irq_mask_reg & mask) != mask) {
+ dev_priv->irq_mask_reg |= mask;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
+}
+
+/**
+ * i915_pipe_enabled - check if a pipe is enabled
+ * @dev: DRM device
+ * @pipe: pipe to check
+ *
+ * Reading certain registers when the pipe is disabled can hang the chip.
+ * Use this routine to make sure the PLL is running and the pipe is active
+ * before reading such registers if unsure.
+ */
+static int
+i915_pipe_enabled(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
+
+ if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
+ return 1;
+
+ return 0;
+}
+
/**
* Emit blits for scheduled buffer swaps.
*
* This function will be called with the HW lock held.
+ * Because this function must grab the ring mutex (dev->struct_mutex),
+ * it can no longer run at soft irq time. We'll fix this when we do
+ * the DRI2 swap buffer work.
*/
static void i915_vblank_tasklet(struct drm_device *dev)
{
@@ -48,8 +94,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
unsigned long irqflags;
struct list_head *list, *tmp, hits, *hit;
int nhits, nrects, slice[2], upper[2], lower[2], i;
- unsigned counter[2] = { atomic_read(&dev->vbl_received),
- atomic_read(&dev->vbl_received2) };
+ unsigned counter[2];
struct drm_drawable_info *drw;
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
u32 cpp = dev_priv->cpp;
@@ -62,6 +107,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)
u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
RING_LOCALS;
+ mutex_lock(&dev->struct_mutex);
+
if (IS_I965G(dev) && sarea_priv->front_tiled) {
cmd |= XY_SRC_COPY_BLT_DST_TILED;
dst_pitch >>= 2;
@@ -71,6 +118,9 @@ static void i915_vblank_tasklet(struct drm_device *dev)
src_pitch >>= 2;
}
+ counter[0] = drm_vblank_count(dev, 0);
+ counter[1] = drm_vblank_count(dev, 1);
+
DRM_DEBUG("\n");
INIT_LIST_HEAD(&hits);
@@ -83,32 +133,33 @@ static void i915_vblank_tasklet(struct drm_device *dev)
list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
drm_i915_vbl_swap_t *vbl_swap =
list_entry(list, drm_i915_vbl_swap_t, head);
+ int pipe = vbl_swap->pipe;
- if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
+ if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
continue;
list_del(list);
dev_priv->swaps_pending--;
+ drm_vblank_put(dev, pipe);
spin_unlock(&dev_priv->swaps_lock);
spin_lock(&dev->drw_lock);
drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
- if (!drw) {
- spin_unlock(&dev->drw_lock);
- drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
- spin_lock(&dev_priv->swaps_lock);
- continue;
- }
-
list_for_each(hit, &hits) {
drm_i915_vbl_swap_t *swap_cmp =
list_entry(hit, drm_i915_vbl_swap_t, head);
struct drm_drawable_info *drw_cmp =
drm_get_drawable_info(dev, swap_cmp->drw_id);
- if (drw_cmp &&
+ /* Make sure both drawables are still
+ * around and have some rectangles before
+ * we look inside to order them for the
+ * blts below.
+ */
+ if (drw_cmp && drw_cmp->num_rects > 0 &&
+ drw && drw->num_rects > 0 &&
drw_cmp->rects[0].y1 > drw->rects[0].y1) {
list_add_tail(list, hit);
break;
@@ -128,6 +179,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
if (nhits == 0) {
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ mutex_unlock(&dev->struct_mutex);
return;
}
@@ -186,6 +238,9 @@ static void i915_vblank_tasklet(struct drm_device *dev)
drw = drm_get_drawable_info(dev, swap_hit->drw_id);
+ /* The drawable may have been destroyed since
+ * the vblank swap was queued
+ */
if (!drw)
continue;
@@ -218,6 +273,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
}
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ mutex_unlock(&dev->struct_mutex);
list_for_each_safe(hit, tmp, &hits) {
drm_i915_vbl_swap_t *swap_hit =
@@ -229,63 +285,157 @@ static void i915_vblank_tasklet(struct drm_device *dev)
}
}
+/* Called from drm generic code, passed a 'crtc', which
+ * we use as a pipe index
+ */
+u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long high_frame;
+ unsigned long low_frame;
+ u32 high1, high2, low, count;
+
+ high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+ low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
+ if (!i915_pipe_enabled(dev, pipe)) {
+ DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe);
+ return 0;
+ }
+
+ /*
+ * High & low register fields aren't synchronized, so make sure
+ * we get a low value that's stable across two reads of the high
+ * register.
+ */
+ do {
+ high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+ PIPE_FRAME_HIGH_SHIFT);
+ low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
+ PIPE_FRAME_LOW_SHIFT);
+ high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+ PIPE_FRAME_HIGH_SHIFT);
+ } while (high1 != high2);
+
+ count = (high1 << 8) | low;
+
+ return count;
+}
+
+void
+i915_vblank_work_handler(struct work_struct *work)
+{
+ drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+ vblank_work);
+ struct drm_device *dev = dev_priv->dev;
+ unsigned long irqflags;
+
+ if (dev->lock.hw_lock == NULL) {
+ i915_vblank_tasklet(dev);
+ return;
+ }
+
+ spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+ dev->locked_tasklet_func = i915_vblank_tasklet;
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+
+ /* Try to get the lock now, if this fails, the lock
+ * holder will execute the tasklet during unlock
+ */
+ if (!drm_lock_take(&dev->lock, DRM_KERNEL_CONTEXT))
+ return;
+
+ dev->lock.lock_time = jiffies;
+ atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
+
+ spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+ dev->locked_tasklet_func = NULL;
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+
+ i915_vblank_tasklet(dev);
+ drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT);
+}
+
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 temp;
+ u32 iir;
u32 pipea_stats, pipeb_stats;
+ int vblank = 0;
- pipea_stats = I915_READ(I915REG_PIPEASTAT);
- pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
+ atomic_inc(&dev_priv->irq_received);
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
+ if (dev->pdev->msi_enabled)
+ I915_WRITE(IMR, ~0);
+ iir = I915_READ(IIR);
- temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
+ if (iir == 0) {
+ if (dev->pdev->msi_enabled) {
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
+ return IRQ_NONE;
+ }
- DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
+ /*
+ * Clear the PIPE(A|B)STAT regs before the IIR otherwise
+ * we may get extra interrupts.
+ */
+ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
+ pipea_stats = I915_READ(PIPEASTAT);
+ if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A))
+ pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
+ else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS)) {
+ vblank++;
+ drm_handle_vblank(dev, 0);
+ }
- if (temp == 0)
- return IRQ_NONE;
+ I915_WRITE(PIPEASTAT, pipea_stats);
+ }
+ if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
+ pipeb_stats = I915_READ(PIPEBSTAT);
+ /* Ack the event */
+ I915_WRITE(PIPEBSTAT, pipeb_stats);
+
+ /* The vblank interrupt gets enabled even if we didn't ask for
+ it, so make sure it's shut down again */
+ if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B))
+ pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
+ else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+ PIPE_VBLANK_INTERRUPT_STATUS)) {
+ vblank++;
+ drm_handle_vblank(dev, 1);
+ }
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
- (void) I915_READ16(I915REG_INT_IDENTITY_R);
- DRM_READMEMORYBARRIER();
+ if (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS)
+ opregion_asle_intr(dev);
+ I915_WRITE(PIPEBSTAT, pipeb_stats);
+ }
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ I915_WRITE(IIR, iir);
+ if (dev->pdev->msi_enabled)
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IIR); /* Flush posted writes */
- if (temp & USER_INT_FLAG)
- DRM_WAKEUP(&dev_priv->irq_queue);
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
- if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
- int vblank_pipe = dev_priv->vblank_pipe;
-
- if ((vblank_pipe &
- (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
- == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
- if (temp & VSYNC_PIPEA_FLAG)
- atomic_inc(&dev->vbl_received);
- if (temp & VSYNC_PIPEB_FLAG)
- atomic_inc(&dev->vbl_received2);
- } else if (((temp & VSYNC_PIPEA_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
- ((temp & VSYNC_PIPEB_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
- atomic_inc(&dev->vbl_received);
-
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
-
- if (dev_priv->swaps_pending > 0)
- drm_locked_tasklet(dev, i915_vblank_tasklet);
- I915_WRITE(I915REG_PIPEASTAT,
- pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
- I915_VBLANK_CLEAR);
- I915_WRITE(I915REG_PIPEBSTAT,
- pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
- I915_VBLANK_CLEAR);
+ if (iir & I915_USER_INTERRUPT) {
+ dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
+ DRM_WAKEUP(&dev_priv->irq_queue);
}
+ if (iir & I915_ASLE_INTERRUPT)
+ opregion_asle_intr(dev);
+
+ if (vblank && dev_priv->swaps_pending > 0)
+ schedule_work(&dev_priv->vblank_work);
+
return IRQ_HANDLED;
}
@@ -298,23 +448,47 @@ static int i915_emit_irq(struct drm_device * dev)
DRM_DEBUG("\n");
- dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
-
+ dev_priv->counter++;
if (dev_priv->counter > 0x7FFFFFFFUL)
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
+ dev_priv->counter = 1;
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
BEGIN_LP_RING(6);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(20);
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
OUT_RING(dev_priv->counter);
OUT_RING(0);
OUT_RING(0);
- OUT_RING(GFX_OP_USER_INTERRUPT);
+ OUT_RING(MI_USER_INTERRUPT);
ADVANCE_LP_RING();
return dev_priv->counter;
}
+void i915_user_irq_get(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
+ i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+ spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+}
+
+void i915_user_irq_put(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
+ if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
+ i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+ spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+}
+
static int i915_wait_irq(struct drm_device * dev, int irq_nr)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -323,55 +497,34 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
READ_BREADCRUMB(dev_priv));
- if (READ_BREADCRUMB(dev_priv) >= irq_nr)
+ if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
+ if (dev_priv->sarea_priv) {
+ dev_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
+ }
return 0;
+ }
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+ i915_user_irq_get(dev);
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
+ i915_user_irq_put(dev);
if (ret == -EBUSY) {
DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
}
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- return ret;
-}
-
-static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence,
- atomic_t *counter)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(counter))
- - *sequence) <= (1<<23)));
-
- *sequence = cur_vblank;
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
return ret;
}
-
-int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
-}
-
-int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
-}
-
/* Needs the lock as it touches the ring.
*/
int i915_irq_emit(struct drm_device *dev, void *data,
@@ -381,14 +534,15 @@ int i915_irq_emit(struct drm_device *dev, void *data,
drm_i915_irq_emit_t *emit = data;
int result;
- LOCK_TEST_WITH_RETURN(dev, file_priv);
+ RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
-
+ mutex_lock(&dev->struct_mutex);
result = i915_emit_irq(dev);
+ mutex_unlock(&dev->struct_mutex);
if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
@@ -414,18 +568,95 @@ int i915_irq_wait(struct drm_device *dev, void *data,
return i915_wait_irq(dev, irqwait->irq_seq);
}
-static void i915_enable_interrupt (struct drm_device *dev)
+/* Called from drm generic code, passed 'crtc' which
+ * we use as a pipe index
+ */
+int i915_enable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 flag;
+ u32 pipestat_reg = 0;
+ u32 pipestat;
+ u32 interrupt = 0;
+ unsigned long irqflags;
- flag = 0;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
- flag |= VSYNC_PIPEA_FLAG;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
- flag |= VSYNC_PIPEB_FLAG;
+ switch (pipe) {
+ case 0:
+ pipestat_reg = PIPEASTAT;
+ interrupt = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ break;
+ case 1:
+ pipestat_reg = PIPEBSTAT;
+ interrupt = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
+ pipe);
+ return 0;
+ }
- I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
+ spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ /* Enabling vblank events in IMR comes before PIPESTAT write, or
+ * there's a race where the PIPESTAT vblank bit gets set to 1, so
+ * the OR of enabled PIPESTAT bits goes to 1, so the PIPExEVENT in
+ * ISR flashes to 1, but the IIR bit doesn't get set to 1 because
+ * IMR masks it. It doesn't ever get set after we clear the masking
+ * in IMR because the ISR bit is edge, not level-triggered, on the
+ * OR of PIPESTAT bits.
+ */
+ i915_enable_irq(dev_priv, interrupt);
+ pipestat = I915_READ(pipestat_reg);
+ if (IS_I965G(dev))
+ pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE;
+ else
+ pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE;
+ /* Clear any stale interrupt status */
+ pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
+ PIPE_VBLANK_INTERRUPT_STATUS);
+ I915_WRITE(pipestat_reg, pipestat);
+ (void) I915_READ(pipestat_reg); /* Posting read */
+ spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+
+ return 0;
+}
+
+/* Called from drm generic code, passed 'crtc' which
+ * we use as a pipe index
+ */
+void i915_disable_vblank(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 pipestat_reg = 0;
+ u32 pipestat;
+ u32 interrupt = 0;
+ unsigned long irqflags;
+
+ switch (pipe) {
+ case 0:
+ pipestat_reg = PIPEASTAT;
+ interrupt = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ break;
+ case 1:
+ pipestat_reg = PIPEBSTAT;
+ interrupt = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ break;
+ default:
+ DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
+ pipe);
+ return;
+ break;
+ }
+
+ spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ i915_disable_irq(dev_priv, interrupt);
+ pipestat = I915_READ(pipestat_reg);
+ pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+ PIPE_VBLANK_INTERRUPT_ENABLE);
+ /* Clear any stale interrupt status */
+ pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
+ PIPE_VBLANK_INTERRUPT_STATUS);
+ I915_WRITE(pipestat_reg, pipestat);
+ (void) I915_READ(pipestat_reg); /* Posting read */
+ spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
}
/* Set the vblank monitor pipe
@@ -434,22 +665,12 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_pipe_t *pipe = data;
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
- if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
- DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe);
- return -EINVAL;
- }
-
- dev_priv->vblank_pipe = pipe->pipe;
-
- i915_enable_interrupt (dev);
-
return 0;
}
@@ -458,19 +679,13 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_pipe_t *pipe = data;
- u16 flag;
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
- flag = I915_READ(I915REG_INT_ENABLE_R);
- pipe->pipe = 0;
- if (flag & VSYNC_PIPEA_FLAG)
- pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
- if (flag & VSYNC_PIPEB_FLAG)
- pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
+ pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
return 0;
}
@@ -483,12 +698,13 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_swap_t *swap = data;
- drm_i915_vbl_swap_t *vbl_swap;
+ drm_i915_vbl_swap_t *vbl_swap, *vbl_old;
unsigned int pipe, seqtype, curseq;
unsigned long irqflags;
struct list_head *list;
+ int ret;
- if (!dev_priv) {
+ if (!dev_priv || !dev_priv->sarea_priv) {
DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
@@ -523,7 +739,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
+ /*
+ * We take the ref here and put it when the swap actually completes
+ * in the tasklet.
+ */
+ ret = drm_vblank_get(dev, pipe);
+ if (ret)
+ return ret;
+ curseq = drm_vblank_count(dev, pipe);
if (seqtype == _DRM_VBLANK_RELATIVE)
swap->sequence += curseq;
@@ -533,46 +756,57 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
swap->sequence = curseq + 1;
} else {
DRM_DEBUG("Missed target sequence\n");
+ drm_vblank_put(dev, pipe);
return -EINVAL;
}
}
+ vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
+
+ if (!vbl_swap) {
+ DRM_ERROR("Failed to allocate memory to queue swap\n");
+ drm_vblank_put(dev, pipe);
+ return -ENOMEM;
+ }
+
+ vbl_swap->drw_id = swap->drawable;
+ vbl_swap->pipe = pipe;
+ vbl_swap->sequence = swap->sequence;
+
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
list_for_each(list, &dev_priv->vbl_swaps.head) {
- vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
+ vbl_old = list_entry(list, drm_i915_vbl_swap_t, head);
- if (vbl_swap->drw_id == swap->drawable &&
- vbl_swap->pipe == pipe &&
- vbl_swap->sequence == swap->sequence) {
+ if (vbl_old->drw_id == swap->drawable &&
+ vbl_old->pipe == pipe &&
+ vbl_old->sequence == swap->sequence) {
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ drm_vblank_put(dev, pipe);
+ drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
DRM_DEBUG("Already scheduled\n");
return 0;
}
}
- spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
-
- if (dev_priv->swaps_pending >= 100) {
+ if (dev_priv->swaps_pending >= 10) {
DRM_DEBUG("Too many swaps queued\n");
+ DRM_DEBUG(" pipe 0: %d pipe 1: %d\n",
+ drm_vblank_count(dev, 0),
+ drm_vblank_count(dev, 1));
+
+ list_for_each(list, &dev_priv->vbl_swaps.head) {
+ vbl_old = list_entry(list, drm_i915_vbl_swap_t, head);
+ DRM_DEBUG("\tdrw %x pipe %d seq %x\n",
+ vbl_old->drw_id, vbl_old->pipe,
+ vbl_old->sequence);
+ }
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ drm_vblank_put(dev, pipe);
+ drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
return -EBUSY;
}
- vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
-
- if (!vbl_swap) {
- DRM_ERROR("Failed to allocate memory to queue swap\n");
- return -ENOMEM;
- }
-
- DRM_DEBUG("\n");
-
- vbl_swap->drw_id = swap->drawable;
- vbl_swap->pipe = pipe;
- vbl_swap->sequence = swap->sequence;
-
- spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
-
list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head);
dev_priv->swaps_pending++;
@@ -587,37 +821,64 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- I915_WRITE16(I915REG_HWSTAM, 0xfffe);
- I915_WRITE16(I915REG_INT_MASK_R, 0x0);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+ I915_WRITE(HWSTAM, 0xeffe);
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
}
-void i915_driver_irq_postinstall(struct drm_device * dev)
+int i915_driver_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int ret, num_pipes = 2;
spin_lock_init(&dev_priv->swaps_lock);
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
+ INIT_WORK(&dev_priv->vblank_work, i915_vblank_work_handler);
dev_priv->swaps_pending = 0;
- if (!dev_priv->vblank_pipe)
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
- i915_enable_interrupt(dev);
+ /* Set initial unmasked IRQs to just the selected vblank pipes. */
+ dev_priv->irq_mask_reg = ~0;
+
+ ret = drm_vblank_init(dev, num_pipes);
+ if (ret)
+ return ret;
+
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+ dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
+ dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+
+ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+
+ dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK;
+
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
+ (void) I915_READ(IER);
+
+ opregion_enable_asle(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
+
+ return 0;
}
void i915_driver_irq_uninstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 temp;
+ u32 temp;
if (!dev_priv)
return;
- I915_WRITE16(I915REG_HWSTAM, 0xffff);
- I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+ dev_priv->vblank_pipe = 0;
+
+ I915_WRITE(HWSTAM, 0xffffffff);
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+ temp = I915_READ(PIPEASTAT);
+ I915_WRITE(PIPEASTAT, temp);
+ temp = I915_READ(PIPEBSTAT);
+ I915_WRITE(PIPEBSTAT, temp);
+ temp = I915_READ(IIR);
+ I915_WRITE(IIR, temp);
}
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
new file mode 100644
index 00000000000..1787a0c7e3a
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_opregion.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2008 Intel Corporation <hong.liu@intel.com>
+ * Copyright 2008 Red Hat <mjg@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, 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 (including the
+ * next paragraph) 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS 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.
+ *
+ */
+
+#include <linux/acpi.h>
+
+#include "drmP.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#define PCI_ASLE 0xe4
+#define PCI_LBPC 0xf4
+#define PCI_ASLS 0xfc
+
+#define OPREGION_SZ (8*1024)
+#define OPREGION_HEADER_OFFSET 0
+#define OPREGION_ACPI_OFFSET 0x100
+#define OPREGION_SWSCI_OFFSET 0x200
+#define OPREGION_ASLE_OFFSET 0x300
+#define OPREGION_VBT_OFFSET 0x1000
+
+#define OPREGION_SIGNATURE "IntelGraphicsMem"
+#define MBOX_ACPI (1<<0)
+#define MBOX_SWSCI (1<<1)
+#define MBOX_ASLE (1<<2)
+
+struct opregion_header {
+ u8 signature[16];
+ u32 size;
+ u32 opregion_ver;
+ u8 bios_ver[32];
+ u8 vbios_ver[16];
+ u8 driver_ver[16];
+ u32 mboxes;
+ u8 reserved[164];
+} __attribute__((packed));
+
+/* OpRegion mailbox #1: public ACPI methods */
+struct opregion_acpi {
+ u32 drdy; /* driver readiness */
+ u32 csts; /* notification status */
+ u32 cevt; /* current event */
+ u8 rsvd1[20];
+ u32 didl[8]; /* supported display devices ID list */
+ u32 cpdl[8]; /* currently presented display list */
+ u32 cadl[8]; /* currently active display list */
+ u32 nadl[8]; /* next active devices list */
+ u32 aslp; /* ASL sleep time-out */
+ u32 tidx; /* toggle table index */
+ u32 chpd; /* current hotplug enable indicator */
+ u32 clid; /* current lid state*/
+ u32 cdck; /* current docking state */
+ u32 sxsw; /* Sx state resume */
+ u32 evts; /* ASL supported events */
+ u32 cnot; /* current OS notification */
+ u32 nrdy; /* driver status */
+ u8 rsvd2[60];
+} __attribute__((packed));
+
+/* OpRegion mailbox #2: SWSCI */
+struct opregion_swsci {
+ u32 scic; /* SWSCI command|status|data */
+ u32 parm; /* command parameters */
+ u32 dslp; /* driver sleep time-out */
+ u8 rsvd[244];
+} __attribute__((packed));
+
+/* OpRegion mailbox #3: ASLE */
+struct opregion_asle {
+ u32 ardy; /* driver readiness */
+ u32 aslc; /* ASLE interrupt command */
+ u32 tche; /* technology enabled indicator */
+ u32 alsi; /* current ALS illuminance reading */
+ u32 bclp; /* backlight brightness to set */
+ u32 pfit; /* panel fitting state */
+ u32 cblv; /* current brightness level */
+ u16 bclm[20]; /* backlight level duty cycle mapping table */
+ u32 cpfm; /* current panel fitting mode */
+ u32 epfm; /* enabled panel fitting modes */
+ u8 plut[74]; /* panel LUT and identifier */
+ u32 pfmb; /* PWM freq and min brightness */
+ u8 rsvd[102];
+} __attribute__((packed));
+
+/* ASLE irq request bits */
+#define ASLE_SET_ALS_ILLUM (1 << 0)
+#define ASLE_SET_BACKLIGHT (1 << 1)
+#define ASLE_SET_PFIT (1 << 2)
+#define ASLE_SET_PWM_FREQ (1 << 3)
+#define ASLE_REQ_MSK 0xf
+
+/* response bits of ASLE irq request */
+#define ASLE_ALS_ILLUM_FAIL (2<<10)
+#define ASLE_BACKLIGHT_FAIL (2<<12)
+#define ASLE_PFIT_FAIL (2<<14)
+#define ASLE_PWM_FREQ_FAIL (2<<16)
+
+/* ASLE backlight brightness to set */
+#define ASLE_BCLP_VALID (1<<31)
+#define ASLE_BCLP_MSK (~(1<<31))
+
+/* ASLE panel fitting request */
+#define ASLE_PFIT_VALID (1<<31)
+#define ASLE_PFIT_CENTER (1<<0)
+#define ASLE_PFIT_STRETCH_TEXT (1<<1)
+#define ASLE_PFIT_STRETCH_GFX (1<<2)
+
+/* PWM frequency and minimum brightness */
+#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
+#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
+#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
+#define ASLE_PFMB_PWM_VALID (1<<31)
+
+#define ASLE_CBLV_VALID (1<<31)
+
+static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct opregion_asle *asle = dev_priv->opregion.asle;
+ u32 blc_pwm_ctl, blc_pwm_ctl2;
+
+ if (!(bclp & ASLE_BCLP_VALID))
+ return ASLE_BACKLIGHT_FAIL;
+
+ bclp &= ASLE_BCLP_MSK;
+ if (bclp < 0 || bclp > 255)
+ return ASLE_BACKLIGHT_FAIL;
+
+ blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
+ blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
+ blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
+
+ if (blc_pwm_ctl2 & BLM_COMBINATION_MODE)
+ pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
+ else
+ I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | ((bclp * 0x101)-1));
+
+ asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
+
+ return 0;
+}
+
+static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
+{
+ /* alsi is the current ALS reading in lux. 0 indicates below sensor
+ range, 0xffff indicates above sensor range. 1-0xfffe are valid */
+ return 0;
+}
+
+static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ if (pfmb & ASLE_PFMB_PWM_VALID) {
+ u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
+ u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
+ blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
+ pwm = pwm >> 9;
+ /* FIXME - what do we do with the PWM? */
+ }
+ return 0;
+}
+
+static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
+{
+ /* Panel fitting is currently controlled by the X code, so this is a
+ noop until modesetting support works fully */
+ if (!(pfit & ASLE_PFIT_VALID))
+ return ASLE_PFIT_FAIL;
+ return 0;
+}
+
+void opregion_asle_intr(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct opregion_asle *asle = dev_priv->opregion.asle;
+ u32 asle_stat = 0;
+ u32 asle_req;
+
+ if (!asle)
+ return;
+
+ asle_req = asle->aslc & ASLE_REQ_MSK;
+
+ if (!asle_req) {
+ DRM_DEBUG("non asle set request??\n");
+ return;
+ }
+
+ if (asle_req & ASLE_SET_ALS_ILLUM)
+ asle_stat |= asle_set_als_illum(dev, asle->alsi);
+
+ if (asle_req & ASLE_SET_BACKLIGHT)
+ asle_stat |= asle_set_backlight(dev, asle->bclp);
+
+ if (asle_req & ASLE_SET_PFIT)
+ asle_stat |= asle_set_pfit(dev, asle->pfit);
+
+ if (asle_req & ASLE_SET_PWM_FREQ)
+ asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
+
+ asle->aslc = asle_stat;
+}
+
+#define ASLE_ALS_EN (1<<0)
+#define ASLE_BLC_EN (1<<1)
+#define ASLE_PFIT_EN (1<<2)
+#define ASLE_PFMB_EN (1<<3)
+
+void opregion_enable_asle(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct opregion_asle *asle = dev_priv->opregion.asle;
+
+ if (asle) {
+ u32 pipeb_stats = I915_READ(PIPEBSTAT);
+ if (IS_MOBILE(dev)) {
+ /* Many devices trigger events with a write to the
+ legacy backlight controller, so we need to ensure
+ that it's able to generate interrupts */
+ I915_WRITE(PIPEBSTAT, pipeb_stats |=
+ I915_LEGACY_BLC_EVENT_ENABLE);
+ i915_enable_irq(dev_priv, I915_ASLE_INTERRUPT |
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
+ } else
+ i915_enable_irq(dev_priv, I915_ASLE_INTERRUPT);
+
+ asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
+ ASLE_PFMB_EN;
+ asle->ardy = 1;
+ }
+}
+
+#define ACPI_EV_DISPLAY_SWITCH (1<<0)
+#define ACPI_EV_LID (1<<1)
+#define ACPI_EV_DOCK (1<<2)
+
+static struct intel_opregion *system_opregion;
+
+int intel_opregion_video_event(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ /* The only video events relevant to opregion are 0x80. These indicate
+ either a docking event, lid switch or display switch request. In
+ Linux, these are handled by the dock, button and video drivers.
+ We might want to fix the video driver to be opregion-aware in
+ future, but right now we just indicate to the firmware that the
+ request has been handled */
+
+ struct opregion_acpi *acpi;
+
+ if (!system_opregion)
+ return NOTIFY_DONE;
+
+ acpi = system_opregion->acpi;
+ acpi->csts = 0;
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block intel_opregion_notifier = {
+ .notifier_call = intel_opregion_video_event,
+};
+
+int intel_opregion_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_opregion *opregion = &dev_priv->opregion;
+ void *base;
+ u32 asls, mboxes;
+ int err = 0;
+
+ pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
+ DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls);
+ if (asls == 0) {
+ DRM_DEBUG("ACPI OpRegion not supported!\n");
+ return -ENOTSUPP;
+ }
+
+ base = ioremap(asls, OPREGION_SZ);
+ if (!base)
+ return -ENOMEM;
+
+ opregion->header = base;
+ if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
+ DRM_DEBUG("opregion signature mismatch\n");
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ mboxes = opregion->header->mboxes;
+ if (mboxes & MBOX_ACPI) {
+ DRM_DEBUG("Public ACPI methods supported\n");
+ opregion->acpi = base + OPREGION_ACPI_OFFSET;
+ } else {
+ DRM_DEBUG("Public ACPI methods not supported\n");
+ err = -ENOTSUPP;
+ goto err_out;
+ }
+ opregion->enabled = 1;
+
+ if (mboxes & MBOX_SWSCI) {
+ DRM_DEBUG("SWSCI supported\n");
+ opregion->swsci = base + OPREGION_SWSCI_OFFSET;
+ }
+ if (mboxes & MBOX_ASLE) {
+ DRM_DEBUG("ASLE supported\n");
+ opregion->asle = base + OPREGION_ASLE_OFFSET;
+ }
+
+ /* Notify BIOS we are ready to handle ACPI video ext notifs.
+ * Right now, all the events are handled by the ACPI video module.
+ * We don't actually need to do anything with them. */
+ opregion->acpi->csts = 0;
+ opregion->acpi->drdy = 1;
+
+ system_opregion = opregion;
+ register_acpi_notifier(&intel_opregion_notifier);
+
+ return 0;
+
+err_out:
+ iounmap(opregion->header);
+ opregion->header = NULL;
+ return err;
+}
+
+void intel_opregion_free(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_opregion *opregion = &dev_priv->opregion;
+
+ if (!opregion->enabled)
+ return;
+
+ opregion->acpi->drdy = 0;
+
+ system_opregion = NULL;
+ unregister_acpi_notifier(&intel_opregion_notifier);
+
+ /* just clear all opregion memory pointers now */
+ iounmap(opregion->header);
+ opregion->header = NULL;
+ opregion->acpi = NULL;
+ opregion->swsci = NULL;
+ opregion->asle = NULL;
+
+ opregion->enabled = 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
new file mode 100644
index 00000000000..5c2d9f206d0
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -0,0 +1,1417 @@
+/* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef _I915_REG_H_
+#define _I915_REG_H_
+
+/*
+ * The Bridge device's PCI config space has information about the
+ * fb aperture size and the amount of pre-reserved memory.
+ */
+#define INTEL_GMCH_CTRL 0x52
+#define INTEL_GMCH_ENABLED 0x4
+#define INTEL_GMCH_MEM_MASK 0x1
+#define INTEL_GMCH_MEM_64M 0x1
+#define INTEL_GMCH_MEM_128M 0
+
+#define INTEL_855_GMCH_GMS_MASK (0x7 << 4)
+#define INTEL_855_GMCH_GMS_DISABLED (0x0 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_1M (0x1 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_4M (0x2 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_8M (0x3 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_16M (0x4 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_32M (0x5 << 4)
+
+#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4)
+#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4)
+
+/* PCI config space */
+
+#define HPLLCC 0xc0 /* 855 only */
+#define GC_CLOCK_CONTROL_MASK (3 << 0)
+#define GC_CLOCK_133_200 (0 << 0)
+#define GC_CLOCK_100_200 (1 << 0)
+#define GC_CLOCK_100_133 (2 << 0)
+#define GC_CLOCK_166_250 (3 << 0)
+#define GCFGC 0xf0 /* 915+ only */
+#define GC_LOW_FREQUENCY_ENABLE (1 << 7)
+#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
+#define GC_DISPLAY_CLOCK_333_MHZ (4 << 4)
+#define GC_DISPLAY_CLOCK_MASK (7 << 4)
+#define LBB 0xf4
+
+/* VGA stuff */
+
+#define VGA_ST01_MDA 0x3ba
+#define VGA_ST01_CGA 0x3da
+
+#define VGA_MSR_WRITE 0x3c2
+#define VGA_MSR_READ 0x3cc
+#define VGA_MSR_MEM_EN (1<<1)
+#define VGA_MSR_CGA_MODE (1<<0)
+
+#define VGA_SR_INDEX 0x3c4
+#define VGA_SR_DATA 0x3c5
+
+#define VGA_AR_INDEX 0x3c0
+#define VGA_AR_VID_EN (1<<5)
+#define VGA_AR_DATA_WRITE 0x3c0
+#define VGA_AR_DATA_READ 0x3c1
+
+#define VGA_GR_INDEX 0x3ce
+#define VGA_GR_DATA 0x3cf
+/* GR05 */
+#define VGA_GR_MEM_READ_MODE_SHIFT 3
+#define VGA_GR_MEM_READ_MODE_PLANE 1
+/* GR06 */
+#define VGA_GR_MEM_MODE_MASK 0xc
+#define VGA_GR_MEM_MODE_SHIFT 2
+#define VGA_GR_MEM_A0000_AFFFF 0
+#define VGA_GR_MEM_A0000_BFFFF 1
+#define VGA_GR_MEM_B0000_B7FFF 2
+#define VGA_GR_MEM_B0000_BFFFF 3
+
+#define VGA_DACMASK 0x3c6
+#define VGA_DACRX 0x3c7
+#define VGA_DACWX 0x3c8
+#define VGA_DACDATA 0x3c9
+
+#define VGA_CR_INDEX_MDA 0x3b4
+#define VGA_CR_DATA_MDA 0x3b5
+#define VGA_CR_INDEX_CGA 0x3d4
+#define VGA_CR_DATA_CGA 0x3d5
+
+/*
+ * Memory interface instructions used by the kernel
+ */
+#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags))
+
+#define MI_NOOP MI_INSTR(0, 0)
+#define MI_USER_INTERRUPT MI_INSTR(0x02, 0)
+#define MI_WAIT_FOR_EVENT MI_INSTR(0x03, 0)
+#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6)
+#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
+#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
+#define MI_FLUSH MI_INSTR(0x04, 0)
+#define MI_READ_FLUSH (1 << 0)
+#define MI_EXE_FLUSH (1 << 1)
+#define MI_NO_WRITE_FLUSH (1 << 2)
+#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */
+#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */
+#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0)
+#define MI_REPORT_HEAD MI_INSTR(0x07, 0)
+#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0)
+#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1)
+#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */
+#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1)
+#define MI_STORE_DWORD_INDEX_SHIFT 2
+#define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, 1)
+#define MI_BATCH_BUFFER MI_INSTR(0x30, 1)
+#define MI_BATCH_NON_SECURE (1)
+#define MI_BATCH_NON_SECURE_I965 (1<<8)
+#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0)
+
+/*
+ * 3D instructions used by the kernel
+ */
+#define GFX_INSTR(opcode, flags) ((0x3 << 29) | ((opcode) << 24) | (flags))
+
+#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24))
+#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define SC_UPDATE_SCISSOR (0x1<<1)
+#define SC_ENABLE_MASK (0x1<<0)
+#define SC_ENABLE (0x1<<0)
+#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16))
+#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define SCI_YMIN_MASK (0xffff<<16)
+#define SCI_XMIN_MASK (0xffff<<0)
+#define SCI_YMAX_MASK (0xffff<<16)
+#define SCI_XMAX_MASK (0xffff<<0)
+#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
+#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4)
+#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
+#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
+#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4)
+#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
+#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
+#define BLT_DEPTH_8 (0<<24)
+#define BLT_DEPTH_16_565 (1<<24)
+#define BLT_DEPTH_16_1555 (2<<24)
+#define BLT_DEPTH_32 (3<<24)
+#define BLT_ROP_GXCOPY (0xcc<<16)
+#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) /* 965+ only */
+#define XY_SRC_COPY_BLT_DST_TILED (1<<11) /* 965+ only */
+#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
+#define ASYNC_FLIP (1<<22)
+#define DISPLAY_PLANE_A (0<<20)
+#define DISPLAY_PLANE_B (1<<20)
+
+/*
+ * Instruction and interrupt control regs
+ */
+
+#define PRB0_TAIL 0x02030
+#define PRB0_HEAD 0x02034
+#define PRB0_START 0x02038
+#define PRB0_CTL 0x0203c
+#define TAIL_ADDR 0x001FFFF8
+#define HEAD_WRAP_COUNT 0xFFE00000
+#define HEAD_WRAP_ONE 0x00200000
+#define HEAD_ADDR 0x001FFFFC
+#define RING_NR_PAGES 0x001FF000
+#define RING_REPORT_MASK 0x00000006
+#define RING_REPORT_64K 0x00000002
+#define RING_REPORT_128K 0x00000004
+#define RING_NO_REPORT 0x00000000
+#define RING_VALID_MASK 0x00000001
+#define RING_VALID 0x00000001
+#define RING_INVALID 0x00000000
+#define PRB1_TAIL 0x02040 /* 915+ only */
+#define PRB1_HEAD 0x02044 /* 915+ only */
+#define PRB1_START 0x02048 /* 915+ only */
+#define PRB1_CTL 0x0204c /* 915+ only */
+#define ACTHD_I965 0x02074
+#define HWS_PGA 0x02080
+#define HWS_ADDRESS_MASK 0xfffff000
+#define HWS_START_ADDRESS_SHIFT 4
+#define IPEIR 0x02088
+#define NOPID 0x02094
+#define HWSTAM 0x02098
+#define SCPD0 0x0209c /* 915+ only */
+#define IER 0x020a0
+#define IIR 0x020a4
+#define IMR 0x020a8
+#define ISR 0x020ac
+#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
+#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
+#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
+#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14)
+#define I915_HWB_OOM_INTERRUPT (1<<13)
+#define I915_SYNC_STATUS_INTERRUPT (1<<12)
+#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
+#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10)
+#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9)
+#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8)
+#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7)
+#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6)
+#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5)
+#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4)
+#define I915_DEBUG_INTERRUPT (1<<2)
+#define I915_USER_INTERRUPT (1<<1)
+#define I915_ASLE_INTERRUPT (1<<0)
+#define EIR 0x020b0
+#define EMR 0x020b4
+#define ESR 0x020b8
+#define INSTPM 0x020c0
+#define ACTHD 0x020c8
+#define FW_BLC 0x020d8
+#define FW_BLC_SELF 0x020e0 /* 915+ only */
+#define MI_ARB_STATE 0x020e4 /* 915+ only */
+#define CACHE_MODE_0 0x02120 /* 915+ only */
+#define CM0_MASK_SHIFT 16
+#define CM0_IZ_OPT_DISABLE (1<<6)
+#define CM0_ZR_OPT_DISABLE (1<<5)
+#define CM0_DEPTH_EVICT_DISABLE (1<<4)
+#define CM0_COLOR_EVICT_DISABLE (1<<3)
+#define CM0_DEPTH_WRITE_DISABLE (1<<1)
+#define CM0_RC_OP_FLUSH_DISABLE (1<<0)
+#define GFX_FLSH_CNTL 0x02170 /* 915+ only */
+
+/*
+ * Framebuffer compression (915+ only)
+ */
+
+#define FBC_CFB_BASE 0x03200 /* 4k page aligned */
+#define FBC_LL_BASE 0x03204 /* 4k page aligned */
+#define FBC_CONTROL 0x03208
+#define FBC_CTL_EN (1<<31)
+#define FBC_CTL_PERIODIC (1<<30)
+#define FBC_CTL_INTERVAL_SHIFT (16)
+#define FBC_CTL_UNCOMPRESSIBLE (1<<14)
+#define FBC_CTL_STRIDE_SHIFT (5)
+#define FBC_CTL_FENCENO (1<<0)
+#define FBC_COMMAND 0x0320c
+#define FBC_CMD_COMPRESS (1<<0)
+#define FBC_STATUS 0x03210
+#define FBC_STAT_COMPRESSING (1<<31)
+#define FBC_STAT_COMPRESSED (1<<30)
+#define FBC_STAT_MODIFIED (1<<29)
+#define FBC_STAT_CURRENT_LINE (1<<0)
+#define FBC_CONTROL2 0x03214
+#define FBC_CTL_FENCE_DBL (0<<4)
+#define FBC_CTL_IDLE_IMM (0<<2)
+#define FBC_CTL_IDLE_FULL (1<<2)
+#define FBC_CTL_IDLE_LINE (2<<2)
+#define FBC_CTL_IDLE_DEBUG (3<<2)
+#define FBC_CTL_CPU_FENCE (1<<1)
+#define FBC_CTL_PLANEA (0<<0)
+#define FBC_CTL_PLANEB (1<<0)
+#define FBC_FENCE_OFF 0x0321b
+
+#define FBC_LL_SIZE (1536)
+
+/*
+ * GPIO regs
+ */
+#define GPIOA 0x5010
+#define GPIOB 0x5014
+#define GPIOC 0x5018
+#define GPIOD 0x501c
+#define GPIOE 0x5020
+#define GPIOF 0x5024
+#define GPIOG 0x5028
+#define GPIOH 0x502c
+# define GPIO_CLOCK_DIR_MASK (1 << 0)
+# define GPIO_CLOCK_DIR_IN (0 << 1)
+# define GPIO_CLOCK_DIR_OUT (1 << 1)
+# define GPIO_CLOCK_VAL_MASK (1 << 2)
+# define GPIO_CLOCK_VAL_OUT (1 << 3)
+# define GPIO_CLOCK_VAL_IN (1 << 4)
+# define GPIO_CLOCK_PULLUP_DISABLE (1 << 5)
+# define GPIO_DATA_DIR_MASK (1 << 8)
+# define GPIO_DATA_DIR_IN (0 << 9)
+# define GPIO_DATA_DIR_OUT (1 << 9)
+# define GPIO_DATA_VAL_MASK (1 << 10)
+# define GPIO_DATA_VAL_OUT (1 << 11)
+# define GPIO_DATA_VAL_IN (1 << 12)
+# define GPIO_DATA_PULLUP_DISABLE (1 << 13)
+
+/*
+ * Clock control & power management
+ */
+
+#define VGA0 0x6000
+#define VGA1 0x6004
+#define VGA_PD 0x6010
+#define VGA0_PD_P2_DIV_4 (1 << 7)
+#define VGA0_PD_P1_DIV_2 (1 << 5)
+#define VGA0_PD_P1_SHIFT 0
+#define VGA0_PD_P1_MASK (0x1f << 0)
+#define VGA1_PD_P2_DIV_4 (1 << 15)
+#define VGA1_PD_P1_DIV_2 (1 << 13)
+#define VGA1_PD_P1_SHIFT 8
+#define VGA1_PD_P1_MASK (0x1f << 8)
+#define DPLL_A 0x06014
+#define DPLL_B 0x06018
+#define DPLL_VCO_ENABLE (1 << 31)
+#define DPLL_DVO_HIGH_SPEED (1 << 30)
+#define DPLL_SYNCLOCK_ENABLE (1 << 29)
+#define DPLL_VGA_MODE_DIS (1 << 28)
+#define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */
+#define DPLLB_MODE_LVDS (2 << 26) /* i915 */
+#define DPLL_MODE_MASK (3 << 26)
+#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */
+#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */
+#define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */
+#define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */
+#define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
+#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
+
+#define I915_FIFO_UNDERRUN_STATUS (1UL<<31)
+#define I915_CRC_ERROR_ENABLE (1UL<<29)
+#define I915_CRC_DONE_ENABLE (1UL<<28)
+#define I915_GMBUS_EVENT_ENABLE (1UL<<27)
+#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25)
+#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
+#define I915_DPST_EVENT_ENABLE (1UL<<23)
+#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
+#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
+#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
+#define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */
+#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16)
+#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
+#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
+#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11)
+#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9)
+#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8)
+#define I915_DPST_EVENT_STATUS (1UL<<7)
+#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6)
+#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5)
+#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4)
+#define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
+#define I915_VBLANK_INTERRUPT_STATUS (1UL<<1)
+#define I915_OVERLAY_UPDATED_STATUS (1UL<<0)
+
+#define SRX_INDEX 0x3c4
+#define SRX_DATA 0x3c5
+#define SR01 1
+#define SR01_SCREEN_OFF (1<<5)
+
+#define PPCR 0x61204
+#define PPCR_ON (1<<0)
+
+#define DVOB 0x61140
+#define DVOB_ON (1<<31)
+#define DVOC 0x61160
+#define DVOC_ON (1<<31)
+#define LVDS 0x61180
+#define LVDS_ON (1<<31)
+
+#define ADPA 0x61100
+#define ADPA_DPMS_MASK (~(3<<10))
+#define ADPA_DPMS_ON (0<<10)
+#define ADPA_DPMS_SUSPEND (1<<10)
+#define ADPA_DPMS_STANDBY (2<<10)
+#define ADPA_DPMS_OFF (3<<10)
+
+#define RING_TAIL 0x00
+#define TAIL_ADDR 0x001FFFF8
+#define RING_HEAD 0x04
+#define HEAD_WRAP_COUNT 0xFFE00000
+#define HEAD_WRAP_ONE 0x00200000
+#define HEAD_ADDR 0x001FFFFC
+#define RING_START 0x08
+#define START_ADDR 0xFFFFF000
+#define RING_LEN 0x0C
+#define RING_NR_PAGES 0x001FF000
+#define RING_REPORT_MASK 0x00000006
+#define RING_REPORT_64K 0x00000002
+#define RING_REPORT_128K 0x00000004
+#define RING_NO_REPORT 0x00000000
+#define RING_VALID_MASK 0x00000001
+#define RING_VALID 0x00000001
+#define RING_INVALID 0x00000000
+
+/* Scratch pad debug 0 reg:
+ */
+#define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000
+/*
+ * The i830 generation, in LVDS mode, defines P1 as the bit number set within
+ * this field (only one bit may be set).
+ */
+#define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000
+#define DPLL_FPA01_P1_POST_DIV_SHIFT 16
+/* i830, required in DVO non-gang */
+#define PLL_P2_DIVIDE_BY_4 (1 << 23)
+#define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */
+#define PLL_REF_INPUT_DREFCLK (0 << 13)
+#define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */
+#define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */
+#define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
+#define PLL_REF_INPUT_MASK (3 << 13)
+#define PLL_LOAD_PULSE_PHASE_SHIFT 9
+/*
+ * Parallel to Serial Load Pulse phase selection.
+ * Selects the phase for the 10X DPLL clock for the PCIe
+ * digital display port. The range is 4 to 13; 10 or more
+ * is just a flip delay. The default is 6
+ */
+#define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
+#define DISPLAY_RATE_SELECT_FPA1 (1 << 8)
+/*
+ * SDVO multiplier for 945G/GM. Not used on 965.
+ */
+#define SDVO_MULTIPLIER_MASK 0x000000ff
+#define SDVO_MULTIPLIER_SHIFT_HIRES 4
+#define SDVO_MULTIPLIER_SHIFT_VGA 0
+#define DPLL_A_MD 0x0601c /* 965+ only */
+/*
+ * UDI pixel divider, controlling how many pixels are stuffed into a packet.
+ *
+ * Value is pixels minus 1. Must be set to 1 pixel for SDVO.
+ */
+#define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000
+#define DPLL_MD_UDI_DIVIDER_SHIFT 24
+/* UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */
+#define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000
+#define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16
+/*
+ * SDVO/UDI pixel multiplier.
+ *
+ * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus
+ * clock rate is 10 times the DPLL clock. At low resolution/refresh rate
+ * modes, the bus rate would be below the limits, so SDVO allows for stuffing
+ * dummy bytes in the datastream at an increased clock rate, with both sides of
+ * the link knowing how many bytes are fill.
+ *
+ * So, for a mode with a dotclock of 65Mhz, we would want to double the clock
+ * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be
+ * set to 130Mhz, and the SDVO multiplier set to 2x in this register and
+ * through an SDVO command.
+ *
+ * This register field has values of multiplication factor minus 1, with
+ * a maximum multiplier of 5 for SDVO.
+ */
+#define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00
+#define DPLL_MD_UDI_MULTIPLIER_SHIFT 8
+/*
+ * SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK.
+ * This best be set to the default value (3) or the CRT won't work. No,
+ * I don't entirely understand what this does...
+ */
+#define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f
+#define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0
+#define DPLL_B_MD 0x06020 /* 965+ only */
+#define FPA0 0x06040
+#define FPA1 0x06044
+#define FPB0 0x06048
+#define FPB1 0x0604c
+#define FP_N_DIV_MASK 0x003f0000
+#define FP_N_DIV_SHIFT 16
+#define FP_M1_DIV_MASK 0x00003f00
+#define FP_M1_DIV_SHIFT 8
+#define FP_M2_DIV_MASK 0x0000003f
+#define FP_M2_DIV_SHIFT 0
+#define DPLL_TEST 0x606c
+#define DPLLB_TEST_SDVO_DIV_1 (0 << 22)
+#define DPLLB_TEST_SDVO_DIV_2 (1 << 22)
+#define DPLLB_TEST_SDVO_DIV_4 (2 << 22)
+#define DPLLB_TEST_SDVO_DIV_MASK (3 << 22)
+#define DPLLB_TEST_N_BYPASS (1 << 19)
+#define DPLLB_TEST_M_BYPASS (1 << 18)
+#define DPLLB_INPUT_BUFFER_ENABLE (1 << 16)
+#define DPLLA_TEST_N_BYPASS (1 << 3)
+#define DPLLA_TEST_M_BYPASS (1 << 2)
+#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0)
+#define D_STATE 0x6104
+#define CG_2D_DIS 0x6200
+#define CG_3D_DIS 0x6204
+
+/*
+ * Palette regs
+ */
+
+#define PALETTE_A 0x0a000
+#define PALETTE_B 0x0a800
+
+/* MCH MMIO space */
+
+/*
+ * MCHBAR mirror.
+ *
+ * This mirrors the MCHBAR MMIO space whose location is determined by
+ * device 0 function 0's pci config register 0x44 or 0x48 and matches it in
+ * every way. It is not accessible from the CP register read instructions.
+ *
+ */
+#define MCHBAR_MIRROR_BASE 0x10000
+
+/** 915-945 and GM965 MCH register controlling DRAM channel access */
+#define DCC 0x10200
+#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0)
+#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC (1 << 0)
+#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED (2 << 0)
+#define DCC_ADDRESSING_MODE_MASK (3 << 0)
+#define DCC_CHANNEL_XOR_DISABLE (1 << 10)
+
+/** 965 MCH register controlling DRAM channel configuration */
+#define C0DRB3 0x10206
+#define C1DRB3 0x10606
+
+/*
+ * Overlay regs
+ */
+
+#define OVADD 0x30000
+#define DOVSTA 0x30008
+#define OC_BUF (0x3<<20)
+#define OGAMC5 0x30010
+#define OGAMC4 0x30014
+#define OGAMC3 0x30018
+#define OGAMC2 0x3001c
+#define OGAMC1 0x30020
+#define OGAMC0 0x30024
+
+/*
+ * Display engine regs
+ */
+
+/* Pipe A timing regs */
+#define HTOTAL_A 0x60000
+#define HBLANK_A 0x60004
+#define HSYNC_A 0x60008
+#define VTOTAL_A 0x6000c
+#define VBLANK_A 0x60010
+#define VSYNC_A 0x60014
+#define PIPEASRC 0x6001c
+#define BCLRPAT_A 0x60020
+
+/* Pipe B timing regs */
+#define HTOTAL_B 0x61000
+#define HBLANK_B 0x61004
+#define HSYNC_B 0x61008
+#define VTOTAL_B 0x6100c
+#define VBLANK_B 0x61010
+#define VSYNC_B 0x61014
+#define PIPEBSRC 0x6101c
+#define BCLRPAT_B 0x61020
+
+/* VGA port control */
+#define ADPA 0x61100
+#define ADPA_DAC_ENABLE (1<<31)
+#define ADPA_DAC_DISABLE 0
+#define ADPA_PIPE_SELECT_MASK (1<<30)
+#define ADPA_PIPE_A_SELECT 0
+#define ADPA_PIPE_B_SELECT (1<<30)
+#define ADPA_USE_VGA_HVPOLARITY (1<<15)
+#define ADPA_SETS_HVPOLARITY 0
+#define ADPA_VSYNC_CNTL_DISABLE (1<<11)
+#define ADPA_VSYNC_CNTL_ENABLE 0
+#define ADPA_HSYNC_CNTL_DISABLE (1<<10)
+#define ADPA_HSYNC_CNTL_ENABLE 0
+#define ADPA_VSYNC_ACTIVE_HIGH (1<<4)
+#define ADPA_VSYNC_ACTIVE_LOW 0
+#define ADPA_HSYNC_ACTIVE_HIGH (1<<3)
+#define ADPA_HSYNC_ACTIVE_LOW 0
+#define ADPA_DPMS_MASK (~(3<<10))
+#define ADPA_DPMS_ON (0<<10)
+#define ADPA_DPMS_SUSPEND (1<<10)
+#define ADPA_DPMS_STANDBY (2<<10)
+#define ADPA_DPMS_OFF (3<<10)
+
+/* Hotplug control (945+ only) */
+#define PORT_HOTPLUG_EN 0x61110
+#define SDVOB_HOTPLUG_INT_EN (1 << 26)
+#define SDVOC_HOTPLUG_INT_EN (1 << 25)
+#define TV_HOTPLUG_INT_EN (1 << 18)
+#define CRT_HOTPLUG_INT_EN (1 << 9)
+#define CRT_HOTPLUG_FORCE_DETECT (1 << 3)
+
+#define PORT_HOTPLUG_STAT 0x61114
+#define CRT_HOTPLUG_INT_STATUS (1 << 11)
+#define TV_HOTPLUG_INT_STATUS (1 << 10)
+#define CRT_HOTPLUG_MONITOR_MASK (3 << 8)
+#define CRT_HOTPLUG_MONITOR_COLOR (3 << 8)
+#define CRT_HOTPLUG_MONITOR_MONO (2 << 8)
+#define CRT_HOTPLUG_MONITOR_NONE (0 << 8)
+#define SDVOC_HOTPLUG_INT_STATUS (1 << 7)
+#define SDVOB_HOTPLUG_INT_STATUS (1 << 6)
+
+/* SDVO port control */
+#define SDVOB 0x61140
+#define SDVOC 0x61160
+#define SDVO_ENABLE (1 << 31)
+#define SDVO_PIPE_B_SELECT (1 << 30)
+#define SDVO_STALL_SELECT (1 << 29)
+#define SDVO_INTERRUPT_ENABLE (1 << 26)
+/**
+ * 915G/GM SDVO pixel multiplier.
+ *
+ * Programmed value is multiplier - 1, up to 5x.
+ *
+ * \sa DPLL_MD_UDI_MULTIPLIER_MASK
+ */
+#define SDVO_PORT_MULTIPLY_MASK (7 << 23)
+#define SDVO_PORT_MULTIPLY_SHIFT 23
+#define SDVO_PHASE_SELECT_MASK (15 << 19)
+#define SDVO_PHASE_SELECT_DEFAULT (6 << 19)
+#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18)
+#define SDVOC_GANG_MODE (1 << 16)
+#define SDVO_BORDER_ENABLE (1 << 7)
+#define SDVOB_PCIE_CONCURRENCY (1 << 3)
+#define SDVO_DETECTED (1 << 2)
+/* Bits to be preserved when writing */
+#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26))
+#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26))
+
+/* DVO port control */
+#define DVOA 0x61120
+#define DVOB 0x61140
+#define DVOC 0x61160
+#define DVO_ENABLE (1 << 31)
+#define DVO_PIPE_B_SELECT (1 << 30)
+#define DVO_PIPE_STALL_UNUSED (0 << 28)
+#define DVO_PIPE_STALL (1 << 28)
+#define DVO_PIPE_STALL_TV (2 << 28)
+#define DVO_PIPE_STALL_MASK (3 << 28)
+#define DVO_USE_VGA_SYNC (1 << 15)
+#define DVO_DATA_ORDER_I740 (0 << 14)
+#define DVO_DATA_ORDER_FP (1 << 14)
+#define DVO_VSYNC_DISABLE (1 << 11)
+#define DVO_HSYNC_DISABLE (1 << 10)
+#define DVO_VSYNC_TRISTATE (1 << 9)
+#define DVO_HSYNC_TRISTATE (1 << 8)
+#define DVO_BORDER_ENABLE (1 << 7)
+#define DVO_DATA_ORDER_GBRG (1 << 6)
+#define DVO_DATA_ORDER_RGGB (0 << 6)
+#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6)
+#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6)
+#define DVO_VSYNC_ACTIVE_HIGH (1 << 4)
+#define DVO_HSYNC_ACTIVE_HIGH (1 << 3)
+#define DVO_BLANK_ACTIVE_HIGH (1 << 2)
+#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */
+#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */
+#define DVO_PRESERVE_MASK (0x7<<24)
+#define DVOA_SRCDIM 0x61124
+#define DVOB_SRCDIM 0x61144
+#define DVOC_SRCDIM 0x61164
+#define DVO_SRCDIM_HORIZONTAL_SHIFT 12
+#define DVO_SRCDIM_VERTICAL_SHIFT 0
+
+/* LVDS port control */
+#define LVDS 0x61180
+/*
+ * Enables the LVDS port. This bit must be set before DPLLs are enabled, as
+ * the DPLL semantics change when the LVDS is assigned to that pipe.
+ */
+#define LVDS_PORT_EN (1 << 31)
+/* Selects pipe B for LVDS data. Must be set on pre-965. */
+#define LVDS_PIPEB_SELECT (1 << 30)
+/*
+ * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per
+ * pixel.
+ */
+#define LVDS_A0A2_CLKA_POWER_MASK (3 << 8)
+#define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8)
+#define LVDS_A0A2_CLKA_POWER_UP (3 << 8)
+/*
+ * Controls the A3 data pair, which contains the additional LSBs for 24 bit
+ * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be
+ * on.
+ */
+#define LVDS_A3_POWER_MASK (3 << 6)
+#define LVDS_A3_POWER_DOWN (0 << 6)
+#define LVDS_A3_POWER_UP (3 << 6)
+/*
+ * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP
+ * is set.
+ */
+#define LVDS_CLKB_POWER_MASK (3 << 4)
+#define LVDS_CLKB_POWER_DOWN (0 << 4)
+#define LVDS_CLKB_POWER_UP (3 << 4)
+/*
+ * Controls the B0-B3 data pairs. This must be set to match the DPLL p2
+ * setting for whether we are in dual-channel mode. The B3 pair will
+ * additionally only be powered up when LVDS_A3_POWER_UP is set.
+ */
+#define LVDS_B0B3_POWER_MASK (3 << 2)
+#define LVDS_B0B3_POWER_DOWN (0 << 2)
+#define LVDS_B0B3_POWER_UP (3 << 2)
+
+/* Panel power sequencing */
+#define PP_STATUS 0x61200
+#define PP_ON (1 << 31)
+/*
+ * Indicates that all dependencies of the panel are on:
+ *
+ * - PLL enabled
+ * - pipe enabled
+ * - LVDS/DVOB/DVOC on
+ */
+#define PP_READY (1 << 30)
+#define PP_SEQUENCE_NONE (0 << 28)
+#define PP_SEQUENCE_ON (1 << 28)
+#define PP_SEQUENCE_OFF (2 << 28)
+#define PP_SEQUENCE_MASK 0x30000000
+#define PP_CONTROL 0x61204
+#define POWER_TARGET_ON (1 << 0)
+#define PP_ON_DELAYS 0x61208
+#define PP_OFF_DELAYS 0x6120c
+#define PP_DIVISOR 0x61210
+
+/* Panel fitting */
+#define PFIT_CONTROL 0x61230
+#define PFIT_ENABLE (1 << 31)
+#define PFIT_PIPE_MASK (3 << 29)
+#define PFIT_PIPE_SHIFT 29
+#define VERT_INTERP_DISABLE (0 << 10)
+#define VERT_INTERP_BILINEAR (1 << 10)
+#define VERT_INTERP_MASK (3 << 10)
+#define VERT_AUTO_SCALE (1 << 9)
+#define HORIZ_INTERP_DISABLE (0 << 6)
+#define HORIZ_INTERP_BILINEAR (1 << 6)
+#define HORIZ_INTERP_MASK (3 << 6)
+#define HORIZ_AUTO_SCALE (1 << 5)
+#define PANEL_8TO6_DITHER_ENABLE (1 << 3)
+#define PFIT_PGM_RATIOS 0x61234
+#define PFIT_VERT_SCALE_MASK 0xfff00000
+#define PFIT_HORIZ_SCALE_MASK 0x0000fff0
+#define PFIT_AUTO_RATIOS 0x61238
+
+/* Backlight control */
+#define BLC_PWM_CTL 0x61254
+#define BACKLIGHT_MODULATION_FREQ_SHIFT (17)
+#define BLC_PWM_CTL2 0x61250 /* 965+ only */
+#define BLM_COMBINATION_MODE (1 << 30)
+/*
+ * This is the most significant 15 bits of the number of backlight cycles in a
+ * complete cycle of the modulated backlight control.
+ *
+ * The actual value is this field multiplied by two.
+ */
+#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17)
+#define BLM_LEGACY_MODE (1 << 16)
+/*
+ * This is the number of cycles out of the backlight modulation cycle for which
+ * the backlight is on.
+ *
+ * This field must be no greater than the number of cycles in the complete
+ * backlight modulation cycle.
+ */
+#define BACKLIGHT_DUTY_CYCLE_SHIFT (0)
+#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff)
+
+/* TV port control */
+#define TV_CTL 0x68000
+/** Enables the TV encoder */
+# define TV_ENC_ENABLE (1 << 31)
+/** Sources the TV encoder input from pipe B instead of A. */
+# define TV_ENC_PIPEB_SELECT (1 << 30)
+/** Outputs composite video (DAC A only) */
+# define TV_ENC_OUTPUT_COMPOSITE (0 << 28)
+/** Outputs SVideo video (DAC B/C) */
+# define TV_ENC_OUTPUT_SVIDEO (1 << 28)
+/** Outputs Component video (DAC A/B/C) */
+# define TV_ENC_OUTPUT_COMPONENT (2 << 28)
+/** Outputs Composite and SVideo (DAC A/B/C) */
+# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE (3 << 28)
+# define TV_TRILEVEL_SYNC (1 << 21)
+/** Enables slow sync generation (945GM only) */
+# define TV_SLOW_SYNC (1 << 20)
+/** Selects 4x oversampling for 480i and 576p */
+# define TV_OVERSAMPLE_4X (0 << 18)
+/** Selects 2x oversampling for 720p and 1080i */
+# define TV_OVERSAMPLE_2X (1 << 18)
+/** Selects no oversampling for 1080p */
+# define TV_OVERSAMPLE_NONE (2 << 18)
+/** Selects 8x oversampling */
+# define TV_OVERSAMPLE_8X (3 << 18)
+/** Selects progressive mode rather than interlaced */
+# define TV_PROGRESSIVE (1 << 17)
+/** Sets the colorburst to PAL mode. Required for non-M PAL modes. */
+# define TV_PAL_BURST (1 << 16)
+/** Field for setting delay of Y compared to C */
+# define TV_YC_SKEW_MASK (7 << 12)
+/** Enables a fix for 480p/576p standard definition modes on the 915GM only */
+# define TV_ENC_SDP_FIX (1 << 11)
+/**
+ * Enables a fix for the 915GM only.
+ *
+ * Not sure what it does.
+ */
+# define TV_ENC_C0_FIX (1 << 10)
+/** Bits that must be preserved by software */
+# define TV_CTL_SAVE ((3 << 8) | (3 << 6))
+# define TV_FUSE_STATE_MASK (3 << 4)
+/** Read-only state that reports all features enabled */
+# define TV_FUSE_STATE_ENABLED (0 << 4)
+/** Read-only state that reports that Macrovision is disabled in hardware*/
+# define TV_FUSE_STATE_NO_MACROVISION (1 << 4)
+/** Read-only state that reports that TV-out is disabled in hardware. */
+# define TV_FUSE_STATE_DISABLED (2 << 4)
+/** Normal operation */
+# define TV_TEST_MODE_NORMAL (0 << 0)
+/** Encoder test pattern 1 - combo pattern */
+# define TV_TEST_MODE_PATTERN_1 (1 << 0)
+/** Encoder test pattern 2 - full screen vertical 75% color bars */
+# define TV_TEST_MODE_PATTERN_2 (2 << 0)
+/** Encoder test pattern 3 - full screen horizontal 75% color bars */
+# define TV_TEST_MODE_PATTERN_3 (3 << 0)
+/** Encoder test pattern 4 - random noise */
+# define TV_TEST_MODE_PATTERN_4 (4 << 0)
+/** Encoder test pattern 5 - linear color ramps */
+# define TV_TEST_MODE_PATTERN_5 (5 << 0)
+/**
+ * This test mode forces the DACs to 50% of full output.
+ *
+ * This is used for load detection in combination with TVDAC_SENSE_MASK
+ */
+# define TV_TEST_MODE_MONITOR_DETECT (7 << 0)
+# define TV_TEST_MODE_MASK (7 << 0)
+
+#define TV_DAC 0x68004
+/**
+ * Reports that DAC state change logic has reported change (RO).
+ *
+ * This gets cleared when TV_DAC_STATE_EN is cleared
+*/
+# define TVDAC_STATE_CHG (1 << 31)
+# define TVDAC_SENSE_MASK (7 << 28)
+/** Reports that DAC A voltage is above the detect threshold */
+# define TVDAC_A_SENSE (1 << 30)
+/** Reports that DAC B voltage is above the detect threshold */
+# define TVDAC_B_SENSE (1 << 29)
+/** Reports that DAC C voltage is above the detect threshold */
+# define TVDAC_C_SENSE (1 << 28)
+/**
+ * Enables DAC state detection logic, for load-based TV detection.
+ *
+ * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set
+ * to off, for load detection to work.
+ */
+# define TVDAC_STATE_CHG_EN (1 << 27)
+/** Sets the DAC A sense value to high */
+# define TVDAC_A_SENSE_CTL (1 << 26)
+/** Sets the DAC B sense value to high */
+# define TVDAC_B_SENSE_CTL (1 << 25)
+/** Sets the DAC C sense value to high */
+# define TVDAC_C_SENSE_CTL (1 << 24)
+/** Overrides the ENC_ENABLE and DAC voltage levels */
+# define DAC_CTL_OVERRIDE (1 << 7)
+/** Sets the slew rate. Must be preserved in software */
+# define ENC_TVDAC_SLEW_FAST (1 << 6)
+# define DAC_A_1_3_V (0 << 4)
+# define DAC_A_1_1_V (1 << 4)
+# define DAC_A_0_7_V (2 << 4)
+# define DAC_A_OFF (3 << 4)
+# define DAC_B_1_3_V (0 << 2)
+# define DAC_B_1_1_V (1 << 2)
+# define DAC_B_0_7_V (2 << 2)
+# define DAC_B_OFF (3 << 2)
+# define DAC_C_1_3_V (0 << 0)
+# define DAC_C_1_1_V (1 << 0)
+# define DAC_C_0_7_V (2 << 0)
+# define DAC_C_OFF (3 << 0)
+
+/**
+ * CSC coefficients are stored in a floating point format with 9 bits of
+ * mantissa and 2 or 3 bits of exponent. The exponent is represented as 2**-n,
+ * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with
+ * -1 (0x3) being the only legal negative value.
+ */
+#define TV_CSC_Y 0x68010
+# define TV_RY_MASK 0x07ff0000
+# define TV_RY_SHIFT 16
+# define TV_GY_MASK 0x00000fff
+# define TV_GY_SHIFT 0
+
+#define TV_CSC_Y2 0x68014
+# define TV_BY_MASK 0x07ff0000
+# define TV_BY_SHIFT 16
+/**
+ * Y attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AY_MASK 0x000003ff
+# define TV_AY_SHIFT 0
+
+#define TV_CSC_U 0x68018
+# define TV_RU_MASK 0x07ff0000
+# define TV_RU_SHIFT 16
+# define TV_GU_MASK 0x000007ff
+# define TV_GU_SHIFT 0
+
+#define TV_CSC_U2 0x6801c
+# define TV_BU_MASK 0x07ff0000
+# define TV_BU_SHIFT 16
+/**
+ * U attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AU_MASK 0x000003ff
+# define TV_AU_SHIFT 0
+
+#define TV_CSC_V 0x68020
+# define TV_RV_MASK 0x0fff0000
+# define TV_RV_SHIFT 16
+# define TV_GV_MASK 0x000007ff
+# define TV_GV_SHIFT 0
+
+#define TV_CSC_V2 0x68024
+# define TV_BV_MASK 0x07ff0000
+# define TV_BV_SHIFT 16
+/**
+ * V attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AV_MASK 0x000007ff
+# define TV_AV_SHIFT 0
+
+#define TV_CLR_KNOBS 0x68028
+/** 2s-complement brightness adjustment */
+# define TV_BRIGHTNESS_MASK 0xff000000
+# define TV_BRIGHTNESS_SHIFT 24
+/** Contrast adjustment, as a 2.6 unsigned floating point number */
+# define TV_CONTRAST_MASK 0x00ff0000
+# define TV_CONTRAST_SHIFT 16
+/** Saturation adjustment, as a 2.6 unsigned floating point number */
+# define TV_SATURATION_MASK 0x0000ff00
+# define TV_SATURATION_SHIFT 8
+/** Hue adjustment, as an integer phase angle in degrees */
+# define TV_HUE_MASK 0x000000ff
+# define TV_HUE_SHIFT 0
+
+#define TV_CLR_LEVEL 0x6802c
+/** Controls the DAC level for black */
+# define TV_BLACK_LEVEL_MASK 0x01ff0000
+# define TV_BLACK_LEVEL_SHIFT 16
+/** Controls the DAC level for blanking */
+# define TV_BLANK_LEVEL_MASK 0x000001ff
+# define TV_BLANK_LEVEL_SHIFT 0
+
+#define TV_H_CTL_1 0x68030
+/** Number of pixels in the hsync. */
+# define TV_HSYNC_END_MASK 0x1fff0000
+# define TV_HSYNC_END_SHIFT 16
+/** Total number of pixels minus one in the line (display and blanking). */
+# define TV_HTOTAL_MASK 0x00001fff
+# define TV_HTOTAL_SHIFT 0
+
+#define TV_H_CTL_2 0x68034
+/** Enables the colorburst (needed for non-component color) */
+# define TV_BURST_ENA (1 << 31)
+/** Offset of the colorburst from the start of hsync, in pixels minus one. */
+# define TV_HBURST_START_SHIFT 16
+# define TV_HBURST_START_MASK 0x1fff0000
+/** Length of the colorburst */
+# define TV_HBURST_LEN_SHIFT 0
+# define TV_HBURST_LEN_MASK 0x0001fff
+
+#define TV_H_CTL_3 0x68038
+/** End of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_END_SHIFT 16
+# define TV_HBLANK_END_MASK 0x1fff0000
+/** Start of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_START_SHIFT 0
+# define TV_HBLANK_START_MASK 0x0001fff
+
+#define TV_V_CTL_1 0x6803c
+/** XXX */
+# define TV_NBR_END_SHIFT 16
+# define TV_NBR_END_MASK 0x07ff0000
+/** XXX */
+# define TV_VI_END_F1_SHIFT 8
+# define TV_VI_END_F1_MASK 0x00003f00
+/** XXX */
+# define TV_VI_END_F2_SHIFT 0
+# define TV_VI_END_F2_MASK 0x0000003f
+
+#define TV_V_CTL_2 0x68040
+/** Length of vsync, in half lines */
+# define TV_VSYNC_LEN_MASK 0x07ff0000
+# define TV_VSYNC_LEN_SHIFT 16
+/** Offset of the start of vsync in field 1, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F1_MASK 0x00007f00
+# define TV_VSYNC_START_F1_SHIFT 8
+/**
+ * Offset of the start of vsync in field 2, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F2_MASK 0x0000007f
+# define TV_VSYNC_START_F2_SHIFT 0
+
+#define TV_V_CTL_3 0x68044
+/** Enables generation of the equalization signal */
+# define TV_EQUAL_ENA (1 << 31)
+/** Length of vsync, in half lines */
+# define TV_VEQ_LEN_MASK 0x007f0000
+# define TV_VEQ_LEN_SHIFT 16
+/** Offset of the start of equalization in field 1, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F1_MASK 0x0007f00
+# define TV_VEQ_START_F1_SHIFT 8
+/**
+ * Offset of the start of equalization in field 2, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F2_MASK 0x000007f
+# define TV_VEQ_START_F2_SHIFT 0
+
+#define TV_V_CTL_4 0x68048
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F1_MASK 0x003f0000
+# define TV_VBURST_START_F1_SHIFT 16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F1_MASK 0x000000ff
+# define TV_VBURST_END_F1_SHIFT 0
+
+#define TV_V_CTL_5 0x6804c
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F2_MASK 0x003f0000
+# define TV_VBURST_START_F2_SHIFT 16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F2_MASK 0x000000ff
+# define TV_VBURST_END_F2_SHIFT 0
+
+#define TV_V_CTL_6 0x68050
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F3_MASK 0x003f0000
+# define TV_VBURST_START_F3_SHIFT 16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F3_MASK 0x000000ff
+# define TV_VBURST_END_F3_SHIFT 0
+
+#define TV_V_CTL_7 0x68054
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F4_MASK 0x003f0000
+# define TV_VBURST_START_F4_SHIFT 16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F4_MASK 0x000000ff
+# define TV_VBURST_END_F4_SHIFT 0
+
+#define TV_SC_CTL_1 0x68060
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA1_EN (1 << 31)
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA2_EN (1 << 30)
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA3_EN (1 << 29)
+/** Sets the subcarrier DDA to reset frequency every other field */
+# define TV_SC_RESET_EVERY_2 (0 << 24)
+/** Sets the subcarrier DDA to reset frequency every fourth field */
+# define TV_SC_RESET_EVERY_4 (1 << 24)
+/** Sets the subcarrier DDA to reset frequency every eighth field */
+# define TV_SC_RESET_EVERY_8 (2 << 24)
+/** Sets the subcarrier DDA to never reset the frequency */
+# define TV_SC_RESET_NEVER (3 << 24)
+/** Sets the peak amplitude of the colorburst.*/
+# define TV_BURST_LEVEL_MASK 0x00ff0000
+# define TV_BURST_LEVEL_SHIFT 16
+/** Sets the increment of the first subcarrier phase generation DDA */
+# define TV_SCDDA1_INC_MASK 0x00000fff
+# define TV_SCDDA1_INC_SHIFT 0
+
+#define TV_SC_CTL_2 0x68064
+/** Sets the rollover for the second subcarrier phase generation DDA */
+# define TV_SCDDA2_SIZE_MASK 0x7fff0000
+# define TV_SCDDA2_SIZE_SHIFT 16
+/** Sets the increent of the second subcarrier phase generation DDA */
+# define TV_SCDDA2_INC_MASK 0x00007fff
+# define TV_SCDDA2_INC_SHIFT 0
+
+#define TV_SC_CTL_3 0x68068
+/** Sets the rollover for the third subcarrier phase generation DDA */
+# define TV_SCDDA3_SIZE_MASK 0x7fff0000
+# define TV_SCDDA3_SIZE_SHIFT 16
+/** Sets the increent of the third subcarrier phase generation DDA */
+# define TV_SCDDA3_INC_MASK 0x00007fff
+# define TV_SCDDA3_INC_SHIFT 0
+
+#define TV_WIN_POS 0x68070
+/** X coordinate of the display from the start of horizontal active */
+# define TV_XPOS_MASK 0x1fff0000
+# define TV_XPOS_SHIFT 16
+/** Y coordinate of the display from the start of vertical active (NBR) */
+# define TV_YPOS_MASK 0x00000fff
+# define TV_YPOS_SHIFT 0
+
+#define TV_WIN_SIZE 0x68074
+/** Horizontal size of the display window, measured in pixels*/
+# define TV_XSIZE_MASK 0x1fff0000
+# define TV_XSIZE_SHIFT 16
+/**
+ * Vertical size of the display window, measured in pixels.
+ *
+ * Must be even for interlaced modes.
+ */
+# define TV_YSIZE_MASK 0x00000fff
+# define TV_YSIZE_SHIFT 0
+
+#define TV_FILTER_CTL_1 0x68080
+/**
+ * Enables automatic scaling calculation.
+ *
+ * If set, the rest of the registers are ignored, and the calculated values can
+ * be read back from the register.
+ */
+# define TV_AUTO_SCALE (1 << 31)
+/**
+ * Disables the vertical filter.
+ *
+ * This is required on modes more than 1024 pixels wide */
+# define TV_V_FILTER_BYPASS (1 << 29)
+/** Enables adaptive vertical filtering */
+# define TV_VADAPT (1 << 28)
+# define TV_VADAPT_MODE_MASK (3 << 26)
+/** Selects the least adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_LEAST (0 << 26)
+/** Selects the moderately adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MODERATE (1 << 26)
+/** Selects the most adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MOST (3 << 26)
+/**
+ * Sets the horizontal scaling factor.
+ *
+ * This should be the fractional part of the horizontal scaling factor divided
+ * by the oversampling rate. TV_HSCALE should be less than 1, and set to:
+ *
+ * (src width - 1) / ((oversample * dest width) - 1)
+ */
+# define TV_HSCALE_FRAC_MASK 0x00003fff
+# define TV_HSCALE_FRAC_SHIFT 0
+
+#define TV_FILTER_CTL_2 0x68084
+/**
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1)
+ */
+# define TV_VSCALE_INT_MASK 0x00038000
+# define TV_VSCALE_INT_SHIFT 15
+/**
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * \sa TV_VSCALE_INT_MASK
+ */
+# define TV_VSCALE_FRAC_MASK 0x00007fff
+# define TV_VSCALE_FRAC_SHIFT 0
+
+#define TV_FILTER_CTL_3 0x68088
+/**
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1))
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ */
+# define TV_VSCALE_IP_INT_MASK 0x00038000
+# define TV_VSCALE_IP_INT_SHIFT 15
+/**
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ *
+ * \sa TV_VSCALE_IP_INT_MASK
+ */
+# define TV_VSCALE_IP_FRAC_MASK 0x00007fff
+# define TV_VSCALE_IP_FRAC_SHIFT 0
+
+#define TV_CC_CONTROL 0x68090
+# define TV_CC_ENABLE (1 << 31)
+/**
+ * Specifies which field to send the CC data in.
+ *
+ * CC data is usually sent in field 0.
+ */
+# define TV_CC_FID_MASK (1 << 27)
+# define TV_CC_FID_SHIFT 27
+/** Sets the horizontal position of the CC data. Usually 135. */
+# define TV_CC_HOFF_MASK 0x03ff0000
+# define TV_CC_HOFF_SHIFT 16
+/** Sets the vertical position of the CC data. Usually 21 */
+# define TV_CC_LINE_MASK 0x0000003f
+# define TV_CC_LINE_SHIFT 0
+
+#define TV_CC_DATA 0x68094
+# define TV_CC_RDY (1 << 31)
+/** Second word of CC data to be transmitted. */
+# define TV_CC_DATA_2_MASK 0x007f0000
+# define TV_CC_DATA_2_SHIFT 16
+/** First word of CC data to be transmitted. */
+# define TV_CC_DATA_1_MASK 0x0000007f
+# define TV_CC_DATA_1_SHIFT 0
+
+#define TV_H_LUMA_0 0x68100
+#define TV_H_LUMA_59 0x681ec
+#define TV_H_CHROMA_0 0x68200
+#define TV_H_CHROMA_59 0x682ec
+#define TV_V_LUMA_0 0x68300
+#define TV_V_LUMA_42 0x683a8
+#define TV_V_CHROMA_0 0x68400
+#define TV_V_CHROMA_42 0x684a8
+
+/* Display & cursor control */
+
+/* Pipe A */
+#define PIPEADSL 0x70000
+#define PIPEACONF 0x70008
+#define PIPEACONF_ENABLE (1<<31)
+#define PIPEACONF_DISABLE 0
+#define PIPEACONF_DOUBLE_WIDE (1<<30)
+#define I965_PIPECONF_ACTIVE (1<<30)
+#define PIPEACONF_SINGLE_WIDE 0
+#define PIPEACONF_PIPE_UNLOCKED 0
+#define PIPEACONF_PIPE_LOCKED (1<<25)
+#define PIPEACONF_PALETTE 0
+#define PIPEACONF_GAMMA (1<<24)
+#define PIPECONF_FORCE_BORDER (1<<25)
+#define PIPECONF_PROGRESSIVE (0 << 21)
+#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
+#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
+#define PIPEASTAT 0x70024
+#define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31)
+#define PIPE_CRC_ERROR_ENABLE (1UL<<29)
+#define PIPE_CRC_DONE_ENABLE (1UL<<28)
+#define PIPE_GMBUS_EVENT_ENABLE (1UL<<27)
+#define PIPE_HOTPLUG_INTERRUPT_ENABLE (1UL<<26)
+#define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25)
+#define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
+#define PIPE_DPST_EVENT_ENABLE (1UL<<23)
+#define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
+#define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
+#define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
+#define PIPE_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) /* pre-965 */
+#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */
+#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16)
+#define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
+#define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
+#define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11)
+#define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10)
+#define PIPE_VSYNC_INTERRUPT_STATUS (1UL<<9)
+#define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL<<8)
+#define PIPE_DPST_EVENT_STATUS (1UL<<7)
+#define PIPE_LEGACY_BLC_EVENT_STATUS (1UL<<6)
+#define PIPE_ODD_FIELD_INTERRUPT_STATUS (1UL<<5)
+#define PIPE_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4)
+#define PIPE_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2) /* pre-965 */
+#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
+#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1)
+#define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0)
+
+#define DSPARB 0x70030
+#define DSPARB_CSTART_MASK (0x7f << 7)
+#define DSPARB_CSTART_SHIFT 7
+#define DSPARB_BSTART_MASK (0x7f)
+#define DSPARB_BSTART_SHIFT 0
+/*
+ * The two pipe frame counter registers are not synchronized, so
+ * reading a stable value is somewhat tricky. The following code
+ * should work:
+ *
+ * do {
+ * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ * PIPE_FRAME_HIGH_SHIFT;
+ * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >>
+ * PIPE_FRAME_LOW_SHIFT);
+ * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ * PIPE_FRAME_HIGH_SHIFT);
+ * } while (high1 != high2);
+ * frame = (high1 << 8) | low1;
+ */
+#define PIPEAFRAMEHIGH 0x70040
+#define PIPE_FRAME_HIGH_MASK 0x0000ffff
+#define PIPE_FRAME_HIGH_SHIFT 0
+#define PIPEAFRAMEPIXEL 0x70044
+#define PIPE_FRAME_LOW_MASK 0xff000000
+#define PIPE_FRAME_LOW_SHIFT 24
+#define PIPE_PIXEL_MASK 0x00ffffff
+#define PIPE_PIXEL_SHIFT 0
+
+/* Cursor A & B regs */
+#define CURACNTR 0x70080
+#define CURSOR_MODE_DISABLE 0x00
+#define CURSOR_MODE_64_32B_AX 0x07
+#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX)
+#define MCURSOR_GAMMA_ENABLE (1 << 26)
+#define CURABASE 0x70084
+#define CURAPOS 0x70088
+#define CURSOR_POS_MASK 0x007FF
+#define CURSOR_POS_SIGN 0x8000
+#define CURSOR_X_SHIFT 0
+#define CURSOR_Y_SHIFT 16
+#define CURBCNTR 0x700c0
+#define CURBBASE 0x700c4
+#define CURBPOS 0x700c8
+
+/* Display A control */
+#define DSPACNTR 0x70180
+#define DISPLAY_PLANE_ENABLE (1<<31)
+#define DISPLAY_PLANE_DISABLE 0
+#define DISPPLANE_GAMMA_ENABLE (1<<30)
+#define DISPPLANE_GAMMA_DISABLE 0
+#define DISPPLANE_PIXFORMAT_MASK (0xf<<26)
+#define DISPPLANE_8BPP (0x2<<26)
+#define DISPPLANE_15_16BPP (0x4<<26)
+#define DISPPLANE_16BPP (0x5<<26)
+#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26)
+#define DISPPLANE_32BPP (0x7<<26)
+#define DISPPLANE_STEREO_ENABLE (1<<25)
+#define DISPPLANE_STEREO_DISABLE 0
+#define DISPPLANE_SEL_PIPE_MASK (1<<24)
+#define DISPPLANE_SEL_PIPE_A 0
+#define DISPPLANE_SEL_PIPE_B (1<<24)
+#define DISPPLANE_SRC_KEY_ENABLE (1<<22)
+#define DISPPLANE_SRC_KEY_DISABLE 0
+#define DISPPLANE_LINE_DOUBLE (1<<20)
+#define DISPPLANE_NO_LINE_DOUBLE 0
+#define DISPPLANE_STEREO_POLARITY_FIRST 0
+#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
+#define DSPAADDR 0x70184
+#define DSPASTRIDE 0x70188
+#define DSPAPOS 0x7018C /* reserved */
+#define DSPASIZE 0x70190
+#define DSPASURF 0x7019C /* 965+ only */
+#define DSPATILEOFF 0x701A4 /* 965+ only */
+
+/* VBIOS flags */
+#define SWF00 0x71410
+#define SWF01 0x71414
+#define SWF02 0x71418
+#define SWF03 0x7141c
+#define SWF04 0x71420
+#define SWF05 0x71424
+#define SWF06 0x71428
+#define SWF10 0x70410
+#define SWF11 0x70414
+#define SWF14 0x71420
+#define SWF30 0x72414
+#define SWF31 0x72418
+#define SWF32 0x7241c
+
+/* Pipe B */
+#define PIPEBDSL 0x71000
+#define PIPEBCONF 0x71008
+#define PIPEBSTAT 0x71024
+#define PIPEBFRAMEHIGH 0x71040
+#define PIPEBFRAMEPIXEL 0x71044
+
+/* Display B control */
+#define DSPBCNTR 0x71180
+#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15)
+#define DISPPLANE_ALPHA_TRANS_DISABLE 0
+#define DISPPLANE_SPRITE_ABOVE_DISPLAY 0
+#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1)
+#define DSPBADDR 0x71184
+#define DSPBSTRIDE 0x71188
+#define DSPBPOS 0x7118C
+#define DSPBSIZE 0x71190
+#define DSPBSURF 0x7119C
+#define DSPBTILEOFF 0x711A4
+
+/* VBIOS regs */
+#define VGACNTRL 0x71400
+# define VGA_DISP_DISABLE (1 << 31)
+# define VGA_2X_MODE (1 << 30)
+# define VGA_PIPE_B_SELECT (1 << 29)
+
+#endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
new file mode 100644
index 00000000000..603fe742ccd
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -0,0 +1,509 @@
+/*
+ *
+ * Copyright 2008 (c) Intel Corporation
+ * Jesse Barnes <jbarnes@virtuousgeek.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (pipe == PIPE_A)
+ return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE);
+ else
+ return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE);
+}
+
+static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+ u32 *array;
+ int i;
+
+ if (!i915_pipe_enabled(dev, pipe))
+ return;
+
+ if (pipe == PIPE_A)
+ array = dev_priv->save_palette_a;
+ else
+ array = dev_priv->save_palette_b;
+
+ for(i = 0; i < 256; i++)
+ array[i] = I915_READ(reg + (i << 2));
+}
+
+static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+ u32 *array;
+ int i;
+
+ if (!i915_pipe_enabled(dev, pipe))
+ return;
+
+ if (pipe == PIPE_A)
+ array = dev_priv->save_palette_a;
+ else
+ array = dev_priv->save_palette_b;
+
+ for(i = 0; i < 256; i++)
+ I915_WRITE(reg + (i << 2), array[i]);
+}
+
+static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE8(index_port, reg);
+ return I915_READ8(data_port);
+}
+
+static u8 i915_read_ar(struct drm_device *dev, u16 st01, u8 reg, u16 palette_enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_READ8(st01);
+ I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
+ return I915_READ8(VGA_AR_DATA_READ);
+}
+
+static void i915_write_ar(struct drm_device *dev, u16 st01, u8 reg, u8 val, u16 palette_enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_READ8(st01);
+ I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
+ I915_WRITE8(VGA_AR_DATA_WRITE, val);
+}
+
+static void i915_write_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg, u8 val)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE8(index_port, reg);
+ I915_WRITE8(data_port, val);
+}
+
+static void i915_save_vga(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int i;
+ u16 cr_index, cr_data, st01;
+
+ /* VGA color palette registers */
+ dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK);
+ /* DACCRX automatically increments during read */
+ I915_WRITE8(VGA_DACRX, 0);
+ /* Read 3 bytes of color data from each index */
+ for (i = 0; i < 256 * 3; i++)
+ dev_priv->saveDACDATA[i] = I915_READ8(VGA_DACDATA);
+
+ /* MSR bits */
+ dev_priv->saveMSR = I915_READ8(VGA_MSR_READ);
+ if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
+ cr_index = VGA_CR_INDEX_CGA;
+ cr_data = VGA_CR_DATA_CGA;
+ st01 = VGA_ST01_CGA;
+ } else {
+ cr_index = VGA_CR_INDEX_MDA;
+ cr_data = VGA_CR_DATA_MDA;
+ st01 = VGA_ST01_MDA;
+ }
+
+ /* CRT controller regs */
+ i915_write_indexed(dev, cr_index, cr_data, 0x11,
+ i915_read_indexed(dev, cr_index, cr_data, 0x11) &
+ (~0x80));
+ for (i = 0; i <= 0x24; i++)
+ dev_priv->saveCR[i] =
+ i915_read_indexed(dev, cr_index, cr_data, i);
+ /* Make sure we don't turn off CR group 0 writes */
+ dev_priv->saveCR[0x11] &= ~0x80;
+
+ /* Attribute controller registers */
+ I915_READ8(st01);
+ dev_priv->saveAR_INDEX = I915_READ8(VGA_AR_INDEX);
+ for (i = 0; i <= 0x14; i++)
+ dev_priv->saveAR[i] = i915_read_ar(dev, st01, i, 0);
+ I915_READ8(st01);
+ I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX);
+ I915_READ8(st01);
+
+ /* Graphics controller registers */
+ for (i = 0; i < 9; i++)
+ dev_priv->saveGR[i] =
+ i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i);
+
+ dev_priv->saveGR[0x10] =
+ i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10);
+ dev_priv->saveGR[0x11] =
+ i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11);
+ dev_priv->saveGR[0x18] =
+ i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18);
+
+ /* Sequencer registers */
+ for (i = 0; i < 8; i++)
+ dev_priv->saveSR[i] =
+ i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i);
+}
+
+static void i915_restore_vga(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int i;
+ u16 cr_index, cr_data, st01;
+
+ /* MSR bits */
+ I915_WRITE8(VGA_MSR_WRITE, dev_priv->saveMSR);
+ if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
+ cr_index = VGA_CR_INDEX_CGA;
+ cr_data = VGA_CR_DATA_CGA;
+ st01 = VGA_ST01_CGA;
+ } else {
+ cr_index = VGA_CR_INDEX_MDA;
+ cr_data = VGA_CR_DATA_MDA;
+ st01 = VGA_ST01_MDA;
+ }
+
+ /* Sequencer registers, don't write SR07 */
+ for (i = 0; i < 7; i++)
+ i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i,
+ dev_priv->saveSR[i]);
+
+ /* CRT controller regs */
+ /* Enable CR group 0 writes */
+ i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]);
+ for (i = 0; i <= 0x24; i++)
+ i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->saveCR[i]);
+
+ /* Graphics controller regs */
+ for (i = 0; i < 9; i++)
+ i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i,
+ dev_priv->saveGR[i]);
+
+ i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10,
+ dev_priv->saveGR[0x10]);
+ i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11,
+ dev_priv->saveGR[0x11]);
+ i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18,
+ dev_priv->saveGR[0x18]);
+
+ /* Attribute controller registers */
+ I915_READ8(st01); /* switch back to index mode */
+ for (i = 0; i <= 0x14; i++)
+ i915_write_ar(dev, st01, i, dev_priv->saveAR[i], 0);
+ I915_READ8(st01); /* switch back to index mode */
+ I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX | 0x20);
+ I915_READ8(st01);
+
+ /* VGA color palette registers */
+ I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK);
+ /* DACCRX automatically increments during read */
+ I915_WRITE8(VGA_DACWX, 0);
+ /* Read 3 bytes of color data from each index */
+ for (i = 0; i < 256 * 3; i++)
+ I915_WRITE8(VGA_DACDATA, dev_priv->saveDACDATA[i]);
+
+}
+
+int i915_save_state(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int i;
+
+ pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
+
+ /* Display arbitration control */
+ dev_priv->saveDSPARB = I915_READ(DSPARB);
+
+ /* Pipe & plane A info */
+ dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
+ dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
+ dev_priv->saveFPA0 = I915_READ(FPA0);
+ dev_priv->saveFPA1 = I915_READ(FPA1);
+ dev_priv->saveDPLL_A = I915_READ(DPLL_A);
+ if (IS_I965G(dev))
+ dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
+ dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
+ dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
+ dev_priv->saveHSYNC_A = I915_READ(HSYNC_A);
+ dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A);
+ dev_priv->saveVBLANK_A = I915_READ(VBLANK_A);
+ dev_priv->saveVSYNC_A = I915_READ(VSYNC_A);
+ dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
+
+ dev_priv->saveDSPACNTR = I915_READ(DSPACNTR);
+ dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE);
+ dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
+ dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
+ dev_priv->saveDSPAADDR = I915_READ(DSPAADDR);
+ if (IS_I965G(dev)) {
+ dev_priv->saveDSPASURF = I915_READ(DSPASURF);
+ dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
+ }
+ i915_save_palette(dev, PIPE_A);
+ dev_priv->savePIPEASTAT = I915_READ(PIPEASTAT);
+
+ /* Pipe & plane B info */
+ dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
+ dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC);
+ dev_priv->saveFPB0 = I915_READ(FPB0);
+ dev_priv->saveFPB1 = I915_READ(FPB1);
+ dev_priv->saveDPLL_B = I915_READ(DPLL_B);
+ if (IS_I965G(dev))
+ dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
+ dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
+ dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
+ dev_priv->saveHSYNC_B = I915_READ(HSYNC_B);
+ dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B);
+ dev_priv->saveVBLANK_B = I915_READ(VBLANK_B);
+ dev_priv->saveVSYNC_B = I915_READ(VSYNC_B);
+ dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
+
+ dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR);
+ dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE);
+ dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
+ dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
+ dev_priv->saveDSPBADDR = I915_READ(DSPBADDR);
+ if (IS_I965GM(dev) || IS_GM45(dev)) {
+ dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
+ dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
+ }
+ i915_save_palette(dev, PIPE_B);
+ dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
+
+ /* CRT state */
+ dev_priv->saveADPA = I915_READ(ADPA);
+
+ /* LVDS state */
+ dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
+ dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
+ dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+ if (IS_I965G(dev))
+ dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
+ if (IS_MOBILE(dev) && !IS_I830(dev))
+ dev_priv->saveLVDS = I915_READ(LVDS);
+ if (!IS_I830(dev) && !IS_845G(dev))
+ dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
+ dev_priv->savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS);
+ dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
+ dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
+
+ /* FIXME: save TV & SDVO state */
+
+ /* FBC state */
+ dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
+ dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
+ dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
+ dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
+
+ /* Interrupt state */
+ dev_priv->saveIIR = I915_READ(IIR);
+ dev_priv->saveIER = I915_READ(IER);
+ dev_priv->saveIMR = I915_READ(IMR);
+
+ /* VGA state */
+ dev_priv->saveVGA0 = I915_READ(VGA0);
+ dev_priv->saveVGA1 = I915_READ(VGA1);
+ dev_priv->saveVGA_PD = I915_READ(VGA_PD);
+ dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
+
+ /* Clock gating state */
+ dev_priv->saveD_STATE = I915_READ(D_STATE);
+ dev_priv->saveCG_2D_DIS = I915_READ(CG_2D_DIS);
+
+ /* Cache mode state */
+ dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
+
+ /* Memory Arbitration state */
+ dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
+
+ /* Scratch space */
+ for (i = 0; i < 16; i++) {
+ dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2));
+ dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
+ }
+ for (i = 0; i < 3; i++)
+ dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
+
+ i915_save_vga(dev);
+
+ return 0;
+}
+
+int i915_restore_state(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int i;
+
+ pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
+
+ I915_WRITE(DSPARB, dev_priv->saveDSPARB);
+
+ /* Pipe & plane A info */
+ /* Prime the clock */
+ if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
+ I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
+ ~DPLL_VCO_ENABLE);
+ DRM_UDELAY(150);
+ }
+ I915_WRITE(FPA0, dev_priv->saveFPA0);
+ I915_WRITE(FPA1, dev_priv->saveFPA1);
+ /* Actually enable it */
+ I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
+ DRM_UDELAY(150);
+ if (IS_I965G(dev))
+ I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
+ DRM_UDELAY(150);
+
+ /* Restore mode */
+ I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
+ I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
+ I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
+ I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
+ I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
+ I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
+ I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
+
+ /* Restore plane info */
+ I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
+ I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
+ I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
+ I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
+ I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
+ if (IS_I965G(dev)) {
+ I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
+ I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
+ }
+
+ I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
+
+ i915_restore_palette(dev, PIPE_A);
+ /* Enable the plane */
+ I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
+ I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
+
+ /* Pipe & plane B info */
+ if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
+ I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
+ ~DPLL_VCO_ENABLE);
+ DRM_UDELAY(150);
+ }
+ I915_WRITE(FPB0, dev_priv->saveFPB0);
+ I915_WRITE(FPB1, dev_priv->saveFPB1);
+ /* Actually enable it */
+ I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
+ DRM_UDELAY(150);
+ if (IS_I965G(dev))
+ I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
+ DRM_UDELAY(150);
+
+ /* Restore mode */
+ I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
+ I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
+ I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
+ I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
+ I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
+ I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
+ I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
+
+ /* Restore plane info */
+ I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
+ I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
+ I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
+ I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
+ I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
+ if (IS_I965G(dev)) {
+ I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
+ I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
+ }
+
+ I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
+
+ i915_restore_palette(dev, PIPE_B);
+ /* Enable the plane */
+ I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
+ I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
+
+ /* CRT state */
+ I915_WRITE(ADPA, dev_priv->saveADPA);
+
+ /* LVDS state */
+ if (IS_I965G(dev))
+ I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
+ if (IS_MOBILE(dev) && !IS_I830(dev))
+ I915_WRITE(LVDS, dev_priv->saveLVDS);
+ if (!IS_I830(dev) && !IS_845G(dev))
+ I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
+
+ I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
+ I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
+ I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS);
+ I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
+ I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
+ I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
+
+ /* FIXME: restore TV & SDVO state */
+
+ /* FBC info */
+ I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
+ I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
+ I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
+ I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
+
+ /* VGA state */
+ I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
+ I915_WRITE(VGA0, dev_priv->saveVGA0);
+ I915_WRITE(VGA1, dev_priv->saveVGA1);
+ I915_WRITE(VGA_PD, dev_priv->saveVGA_PD);
+ DRM_UDELAY(150);
+
+ /* Clock gating state */
+ I915_WRITE (D_STATE, dev_priv->saveD_STATE);
+ I915_WRITE (CG_2D_DIS, dev_priv->saveCG_2D_DIS);
+
+ /* Cache mode state */
+ I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
+
+ /* Memory arbitration state */
+ I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
+
+ for (i = 0; i < 16; i++) {
+ I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]);
+ I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
+ }
+ for (i = 0; i < 3; i++)
+ I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
+
+ i915_restore_vga(dev);
+
+ return 0;
+}
+
diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c
index 5572939fc7d..97ee566ef74 100644
--- a/drivers/gpu/drm/mga/mga_drv.c
+++ b/drivers/gpu/drm/mga/mga_drv.c
@@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
- DRIVER_IRQ_VBL,
+ DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
.dev_priv_size = sizeof(drm_mga_buf_priv_t),
.load = mga_driver_load,
.unload = mga_driver_unload,
.lastclose = mga_driver_lastclose,
.dma_quiescent = mga_driver_dma_quiescent,
.device_is_agp = mga_driver_device_is_agp,
- .vblank_wait = mga_driver_vblank_wait,
+ .get_vblank_counter = mga_get_vblank_counter,
+ .enable_vblank = mga_enable_vblank,
+ .disable_vblank = mga_disable_vblank,
.irq_preinstall = mga_driver_irq_preinstall,
.irq_postinstall = mga_driver_irq_postinstall,
.irq_uninstall = mga_driver_irq_uninstall,
@@ -64,20 +65,20 @@ static struct drm_driver driver = {
.ioctls = mga_ioctls,
.dma_ioctl = mga_dma_buffers,
.fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .ioctl = drm_ioctl,
- .mmap = drm_mmap,
- .poll = drm_poll,
- .fasync = drm_fasync,
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .ioctl = drm_ioctl,
+ .mmap = drm_mmap,
+ .poll = drm_poll,
+ .fasync = drm_fasync,
#ifdef CONFIG_COMPAT
- .compat_ioctl = mga_compat_ioctl,
+ .compat_ioctl = mga_compat_ioctl,
#endif
- },
+ },
.pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
},
.name = DRIVER_NAME,
diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h
index f6ebd24bd58..88257c276eb 100644
--- a/drivers/gpu/drm/mga/mga_drv.h
+++ b/drivers/gpu/drm/mga/mga_drv.h
@@ -120,6 +120,7 @@ typedef struct drm_mga_private {
u32 clear_cmd;
u32 maccess;
+ atomic_t vbl_received; /**< Number of vblanks received. */
wait_queue_head_t fence_queue;
atomic_t last_fence_retired;
u32 next_fence_to_post;
@@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
extern int mga_warp_init(drm_mga_private_t * dev_priv);
/* mga_irq.c */
+extern int mga_enable_vblank(struct drm_device *dev, int crtc);
+extern void mga_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
extern void mga_driver_irq_preinstall(struct drm_device * dev);
-extern void mga_driver_irq_postinstall(struct drm_device * dev);
+extern int mga_driver_irq_postinstall(struct drm_device *dev);
extern void mga_driver_irq_uninstall(struct drm_device * dev);
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
diff --git a/drivers/gpu/drm/mga/mga_irq.c b/drivers/gpu/drm/mga/mga_irq.c
index 9302cb8f0f8..bab42f41188 100644
--- a/drivers/gpu/drm/mga/mga_irq.c
+++ b/drivers/gpu/drm/mga/mga_irq.c
@@ -1,5 +1,6 @@
/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
- *
+ */
+/*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
@@ -35,6 +36,18 @@
#include "mga_drm.h"
#include "mga_drv.h"
+u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+ const drm_mga_private_t *const dev_priv =
+ (drm_mga_private_t *) dev->dev_private;
+
+ if (crtc != 0)
+ return 0;
+
+ return atomic_read(&dev_priv->vbl_received);
+}
+
+
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
/* VBLANK interrupt */
if (status & MGA_VLINEPEN) {
MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
- atomic_inc(&dev->vbl_received);
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ atomic_inc(&dev_priv->vbl_received);
+ drm_handle_vblank(dev, 0);
handled = 1;
}
@@ -58,6 +70,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
const u32 prim_end = MGA_READ(MGA_PRIMEND);
+
MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
/* In addition to clearing the interrupt-pending bit, we
@@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
handled = 1;
}
- if (handled) {
+ if (handled)
return IRQ_HANDLED;
- }
return IRQ_NONE;
}
-int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int mga_enable_vblank(struct drm_device *dev, int crtc)
{
- unsigned int cur_vblank;
- int ret = 0;
+ drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received))
- - *sequence) <= (1 << 23)));
+ if (crtc != 0) {
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+ crtc);
+ return 0;
+ }
- *sequence = cur_vblank;
+ MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+ return 0;
+}
- return ret;
+
+void mga_disable_vblank(struct drm_device *dev, int crtc)
+{
+ if (crtc != 0) {
+ DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
+ crtc);
+ }
+
+ /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have
+ * a nice hardware counter that tracks the number of refreshes when
+ * the interrupt is disabled, and the kernel doesn't know the refresh
+ * rate to calculate an estimate.
+ */
+ /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
}
int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
@@ -125,14 +149,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
MGA_WRITE(MGA_ICLEAR, ~0);
}
-void mga_driver_irq_postinstall(struct drm_device * dev)
+int mga_driver_irq_postinstall(struct drm_device *dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
+ int ret;
+
+ ret = drm_vblank_init(dev, 1);
+ if (ret)
+ return ret;
DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
- /* Turn on vertical blank interrupt and soft trap interrupt. */
- MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+ /* Turn on soft trap interrupt. Vertical blank interrupts are enabled
+ * in mga_enable_vblank.
+ */
+ MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
+ return 0;
}
void mga_driver_irq_uninstall(struct drm_device * dev)
diff --git a/drivers/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c
index d3f8aade07b..b710fab21cb 100644
--- a/drivers/gpu/drm/mga/mga_state.c
+++ b/drivers/gpu/drm/mga/mga_state.c
@@ -1022,7 +1022,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil
switch (param->param) {
case MGA_PARAM_IRQ_NR:
- value = dev->irq;
+ value = drm_dev_to_irq(dev);
break;
case MGA_PARAM_CARD_TYPE:
value = dev_priv->chipset;
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c
index 6108e7587e1..3265d53ba91 100644
--- a/drivers/gpu/drm/r128/r128_drv.c
+++ b/drivers/gpu/drm/r128/r128_drv.c
@@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
- DRIVER_IRQ_VBL,
+ DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
.dev_priv_size = sizeof(drm_r128_buf_priv_t),
.preclose = r128_driver_preclose,
.lastclose = r128_driver_lastclose,
- .vblank_wait = r128_driver_vblank_wait,
+ .get_vblank_counter = r128_get_vblank_counter,
+ .enable_vblank = r128_enable_vblank,
+ .disable_vblank = r128_disable_vblank,
.irq_preinstall = r128_driver_irq_preinstall,
.irq_postinstall = r128_driver_irq_postinstall,
.irq_uninstall = r128_driver_irq_uninstall,
@@ -59,21 +60,20 @@ static struct drm_driver driver = {
.ioctls = r128_ioctls,
.dma_ioctl = r128_cce_buffers,
.fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .ioctl = drm_ioctl,
- .mmap = drm_mmap,
- .poll = drm_poll,
- .fasync = drm_fasync,
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .ioctl = drm_ioctl,
+ .mmap = drm_mmap,
+ .poll = drm_poll,
+ .fasync = drm_fasync,
#ifdef CONFIG_COMPAT
- .compat_ioctl = r128_compat_ioctl,
+ .compat_ioctl = r128_compat_ioctl,
#endif
},
-
.pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
},
.name = DRIVER_NAME,
@@ -87,6 +87,7 @@ static struct drm_driver driver = {
static int __init r128_init(void)
{
driver.num_ioctls = r128_max_ioctl;
+
return drm_init(&driver);
}
diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h
index 011105e51ac..5898b274279 100644
--- a/drivers/gpu/drm/r128/r128_drv.h
+++ b/drivers/gpu/drm/r128/r128_drv.h
@@ -29,7 +29,7 @@
* Rickard E. (Rik) Faith <faith@valinux.com>
* Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com>
- * Michel Dänzer <daenzerm@student.ethz.ch>
+ * Michel D�zer <daenzerm@student.ethz.ch>
*/
#ifndef __R128_DRV_H__
@@ -97,6 +97,8 @@ typedef struct drm_r128_private {
u32 crtc_offset;
u32 crtc_offset_cntl;
+ atomic_t vbl_received;
+
u32 color_fmt;
unsigned int front_offset;
unsigned int front_pitch;
@@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
extern int r128_do_cleanup_cce(struct drm_device * dev);
-extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
-
+extern int r128_enable_vblank(struct drm_device *dev, int crtc);
+extern void r128_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
extern void r128_driver_irq_preinstall(struct drm_device * dev);
-extern void r128_driver_irq_postinstall(struct drm_device * dev);
+extern int r128_driver_irq_postinstall(struct drm_device *dev);
extern void r128_driver_irq_uninstall(struct drm_device * dev);
extern void r128_driver_lastclose(struct drm_device * dev);
extern void r128_driver_preclose(struct drm_device * dev,
diff --git a/drivers/gpu/drm/r128/r128_irq.c b/drivers/gpu/drm/r128/r128_irq.c
index c76fdca7662..d7349012a68 100644
--- a/drivers/gpu/drm/r128/r128_irq.c
+++ b/drivers/gpu/drm/r128/r128_irq.c
@@ -35,6 +35,16 @@
#include "r128_drm.h"
#include "r128_drv.h"
+u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+ const drm_r128_private_t *dev_priv = dev->dev_private;
+
+ if (crtc != 0)
+ return 0;
+
+ return atomic_read(&dev_priv->vbl_received);
+}
+
irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
/* VBLANK interrupt */
if (status & R128_CRTC_VBLANK_INT) {
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
- atomic_inc(&dev->vbl_received);
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ atomic_inc(&dev_priv->vbl_received);
+ drm_handle_vblank(dev, 0);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
-int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int r128_enable_vblank(struct drm_device *dev, int crtc)
{
- unsigned int cur_vblank;
- int ret = 0;
+ drm_r128_private_t *dev_priv = dev->dev_private;
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received))
- - *sequence) <= (1 << 23)));
+ if (crtc != 0) {
+ DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
+ return -EINVAL;
+ }
- *sequence = cur_vblank;
+ R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
+ return 0;
+}
+
+void r128_disable_vblank(struct drm_device *dev, int crtc)
+{
+ if (crtc != 0)
+ DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
- return ret;
+ /*
+ * FIXME: implement proper interrupt disable by using the vblank
+ * counter register (if available)
+ *
+ * R128_WRITE(R128_GEN_INT_CNTL,
+ * R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
+ */
}
void r128_driver_irq_preinstall(struct drm_device * dev)
@@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
}
-void r128_driver_irq_postinstall(struct drm_device * dev)
+int r128_driver_irq_postinstall(struct drm_device *dev)
{
- drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
-
- /* Turn on VBL interrupt */
- R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
+ return drm_vblank_init(dev, 1);
}
void r128_driver_irq_uninstall(struct drm_device * dev)
diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c
index 51a9afce7b9..f7a5b574076 100644
--- a/drivers/gpu/drm/r128/r128_state.c
+++ b/drivers/gpu/drm/r128/r128_state.c
@@ -1629,7 +1629,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi
switch (param->param) {
case R128_PARAM_IRQ_NR:
- value = dev->irq;
+ value = drm_dev_to_irq(dev);
break;
default:
return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 248ab4a7d39..59a2132a8f5 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -71,7 +71,8 @@ static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
return RS690_READ_MCIND(dev_priv, addr);
else
return RS480_READ_MCIND(dev_priv, addr);
@@ -82,7 +83,8 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
@@ -94,7 +96,8 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
@@ -106,7 +109,8 @@ static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_lo
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
@@ -122,15 +126,17 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
- } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
+ } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
- } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480) {
+ } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
- RADEON_WRITE(RS480_AGP_BASE_2, 0);
+ RADEON_WRITE(RS480_AGP_BASE_2, agp_base_hi);
} else {
RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200)
@@ -347,6 +353,7 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
DRM_INFO("Loading R300 Microcode\n");
for (i = 0; i < 256; i++) {
@@ -356,6 +363,7 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
R300_cp_microcode[i][0]);
}
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R423) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV410)) {
DRM_INFO("Loading R400 Microcode\n");
for (i = 0; i < 256; i++) {
@@ -364,8 +372,9 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
R420_cp_microcode[i][0]);
}
- } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
- DRM_INFO("Loading RS690 Microcode\n");
+ } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
+ DRM_INFO("Loading RS690/RS740 Microcode\n");
for (i = 0; i < 256; i++) {
RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
RS690_cp_microcode[i][1]);
@@ -626,8 +635,6 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
dev_priv->ring.size_l2qw);
#endif
- /* Start with assuming that writeback doesn't work */
- dev_priv->writeback_works = 0;
/* Initialize the scratch register pointer. This will cause
* the scratch register values to be written out to memory
@@ -646,8 +653,18 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
/* Turn on bus mastering */
- tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
- RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+ if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
+ /* rs400, rs690/rs740 */
+ tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS400_BUS_MASTER_DIS;
+ RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+ } else if (!(((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R423))) {
+ /* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */
+ tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+ RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+ } /* PCIE cards appears to not need this */
dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
@@ -674,6 +691,9 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
{
u32 tmp;
+ /* Start with assuming that writeback doesn't work */
+ dev_priv->writeback_works = 0;
+
/* Writeback doesn't seem to work everywhere, test it here and possibly
* enable it if it appears to work
*/
@@ -719,7 +739,8 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
dev_priv->gart_size);
temp = IGP_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL);
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN |
RS690_BLOCK_GFX_D3_EN));
else
@@ -812,6 +833,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
u32 tmp;
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740) ||
(dev_priv->flags & RADEON_IS_IGPGART)) {
radeon_set_igpgart(dev_priv, on);
return;
@@ -1286,7 +1308,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
radeon_cp_init_ring_buffer(dev, dev_priv);
radeon_do_engine_reset(dev);
- radeon_enable_interrupt(dev);
+ radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
DRM_DEBUG("radeon_do_resume_cp() complete\n");
@@ -1708,6 +1730,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
case CHIP_R300:
case CHIP_R350:
case CHIP_R420:
+ case CHIP_R423:
case CHIP_RV410:
case CHIP_RV515:
case CHIP_R520:
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 637bd7faf13..71af746a4e4 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -52,6 +52,28 @@ static int dri_library_name(struct drm_device *dev, char *buf)
"r300"));
}
+static int radeon_suspend(struct drm_device *dev, pm_message_t state)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ /* Disable *all* interrupts */
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+ RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
+ RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
+ return 0;
+}
+
+static int radeon_resume(struct drm_device *dev)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ /* Restore interrupt registers */
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+ RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
+ RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
+ return 0;
+}
+
static struct pci_device_id pciidlist[] = {
radeon_PCI_IDS
};
@@ -59,8 +81,7 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED |
- DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
+ DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
.dev_priv_size = sizeof(drm_radeon_buf_priv_t),
.load = radeon_driver_load,
.firstopen = radeon_driver_firstopen,
@@ -69,8 +90,11 @@ static struct drm_driver driver = {
.postclose = radeon_driver_postclose,
.lastclose = radeon_driver_lastclose,
.unload = radeon_driver_unload,
- .vblank_wait = radeon_driver_vblank_wait,
- .vblank_wait2 = radeon_driver_vblank_wait2,
+ .suspend = radeon_suspend,
+ .resume = radeon_resume,
+ .get_vblank_counter = radeon_get_vblank_counter,
+ .enable_vblank = radeon_enable_vblank,
+ .disable_vblank = radeon_disable_vblank,
.dri_library_name = dri_library_name,
.irq_preinstall = radeon_driver_irq_preinstall,
.irq_postinstall = radeon_driver_irq_postinstall,
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index 09938169317..4dbb813910c 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -122,9 +122,12 @@ enum radeon_family {
CHIP_RV350,
CHIP_RV380,
CHIP_R420,
+ CHIP_R423,
CHIP_RV410,
+ CHIP_RS400,
CHIP_RS480,
CHIP_RS690,
+ CHIP_RS740,
CHIP_RV515,
CHIP_R520,
CHIP_RV530,
@@ -378,17 +381,17 @@ extern void radeon_mem_release(struct drm_file *file_priv,
struct mem_block *heap);
/* radeon_irq.c */
+extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state);
extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_do_release(struct drm_device * dev);
-extern int radeon_driver_vblank_wait(struct drm_device * dev,
- unsigned int *sequence);
-extern int radeon_driver_vblank_wait2(struct drm_device * dev,
- unsigned int *sequence);
+extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);
+extern int radeon_enable_vblank(struct drm_device *dev, int crtc);
+extern void radeon_disable_vblank(struct drm_device *dev, int crtc);
extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
extern void radeon_driver_irq_preinstall(struct drm_device * dev);
-extern void radeon_driver_irq_postinstall(struct drm_device * dev);
+extern int radeon_driver_irq_postinstall(struct drm_device *dev);
extern void radeon_driver_irq_uninstall(struct drm_device * dev);
extern void radeon_enable_interrupt(struct drm_device *dev);
extern int radeon_vblank_crtc_get(struct drm_device *dev);
@@ -397,19 +400,22 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
extern int radeon_driver_unload(struct drm_device *dev);
extern int radeon_driver_firstopen(struct drm_device *dev);
-extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv);
-extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp);
+extern void radeon_driver_preclose(struct drm_device *dev,
+ struct drm_file *file_priv);
+extern void radeon_driver_postclose(struct drm_device *dev,
+ struct drm_file *file_priv);
extern void radeon_driver_lastclose(struct drm_device * dev);
-extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv);
+extern int radeon_driver_open(struct drm_device *dev,
+ struct drm_file *file_priv);
extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
/* r300_cmdbuf.c */
extern void r300_init_reg_flags(struct drm_device *dev);
-extern int r300_do_cp_cmdbuf(struct drm_device * dev,
+extern int r300_do_cp_cmdbuf(struct drm_device *dev,
struct drm_file *file_priv,
- drm_radeon_kcmd_buffer_t * cmdbuf);
+ drm_radeon_kcmd_buffer_t *cmdbuf);
/* Flags for stats.boxes
*/
@@ -434,8 +440,31 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
# define RADEON_SCISSOR_1_ENABLE (1 << 29)
# define RADEON_SCISSOR_2_ENABLE (1 << 30)
+/*
+ * PCIE radeons (rv370/rv380, rv410, r423/r430/r480, r5xx)
+ * don't have an explicit bus mastering disable bit. It's handled
+ * by the PCI D-states. PMI_BM_DIS disables D-state bus master
+ * handling, not bus mastering itself.
+ */
#define RADEON_BUS_CNTL 0x0030
+/* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */
# define RADEON_BUS_MASTER_DIS (1 << 6)
+/* rs400, rs690/rs740 */
+# define RS400_BUS_MASTER_DIS (1 << 14)
+# define RS400_MSI_REARM (1 << 20)
+/* see RS480_MSI_REARM in AIC_CNTL for rs480 */
+
+#define RADEON_BUS_CNTL1 0x0034
+# define RADEON_PMI_BM_DIS (1 << 2)
+# define RADEON_PMI_INT_DIS (1 << 3)
+
+#define RV370_BUS_CNTL 0x004c
+# define RV370_PMI_BM_DIS (1 << 5)
+# define RV370_PMI_INT_DIS (1 << 6)
+
+#define RADEON_MSI_REARM_EN 0x0160
+/* rv370/rv380, rv410, r423/r430/r480, r5xx */
+# define RV370_MSI_REARM_EN (1 << 0)
#define RADEON_CLOCK_CNTL_DATA 0x000c
# define RADEON_PLL_WR_EN (1 << 7)
@@ -623,6 +652,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
# define RADEON_SW_INT_TEST (1 << 25)
# define RADEON_SW_INT_TEST_ACK (1 << 25)
# define RADEON_SW_INT_FIRE (1 << 26)
+# define R500_DISPLAY_INT_STATUS (1 << 0)
#define RADEON_HOST_PATH_CNTL 0x0130
# define RADEON_HDP_SOFT_RESET (1 << 26)
@@ -907,6 +937,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
#define RADEON_AIC_CNTL 0x01d0
# define RADEON_PCIGART_TRANSLATE_EN (1 << 0)
+# define RS480_MSI_REARM (1 << 3)
#define RADEON_AIC_STAT 0x01d4
#define RADEON_AIC_PT_BASE 0x01d8
#define RADEON_AIC_LO_ADDR 0x01dc
@@ -1116,6 +1147,9 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
#define R200_VAP_PVS_CNTL_1 0x22D0
+#define RADEON_CRTC_CRNT_FRAME 0x0214
+#define RADEON_CRTC2_CRNT_FRAME 0x0314
+
#define R500_D1CRTC_STATUS 0x609c
#define R500_D2CRTC_STATUS 0x689c
#define R500_CRTC_V_BLANK (1<<0)
@@ -1200,7 +1234,8 @@ do { \
#define IGP_WRITE_MCIND(addr, val) \
do { \
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) \
+ if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || \
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) \
RS690_WRITE_MCIND(addr, val); \
else \
RS480_WRITE_MCIND(addr, val); \
diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c
index ee40d197deb..5079f7054a2 100644
--- a/drivers/gpu/drm/radeon/radeon_irq.c
+++ b/drivers/gpu/drm/radeon/radeon_irq.c
@@ -27,7 +27,7 @@
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
- * Michel Dänzer <michel@daenzer.net>
+ * Michel D�zer <michel@daenzer.net>
*/
#include "drmP.h"
@@ -35,12 +35,128 @@
#include "radeon_drm.h"
#include "radeon_drv.h"
-static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
- u32 mask)
+void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
{
- u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ if (state)
+ dev_priv->irq_enable_reg |= mask;
+ else
+ dev_priv->irq_enable_reg &= ~mask;
+
+ RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
+}
+
+static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ if (state)
+ dev_priv->r500_disp_irq_reg |= mask;
+ else
+ dev_priv->r500_disp_irq_reg &= ~mask;
+
+ RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
+}
+
+int radeon_enable_vblank(struct drm_device *dev, int crtc)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+ switch (crtc) {
+ case 0:
+ r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1);
+ break;
+ case 1:
+ r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1);
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+ crtc);
+ return EINVAL;
+ }
+ } else {
+ switch (crtc) {
+ case 0:
+ radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
+ break;
+ case 1:
+ radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+ crtc);
+ return EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+void radeon_disable_vblank(struct drm_device *dev, int crtc)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+ switch (crtc) {
+ case 0:
+ r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0);
+ break;
+ case 1:
+ r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0);
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+ crtc);
+ break;
+ }
+ } else {
+ switch (crtc) {
+ case 0:
+ radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
+ break;
+ case 1:
+ radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+ crtc);
+ break;
+ }
+ }
+}
+
+static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int)
+{
+ u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS);
+ u32 irq_mask = RADEON_SW_INT_TEST;
+
+ *r500_disp_int = 0;
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+ /* vbl interrupts in a different place */
+
+ if (irqs & R500_DISPLAY_INT_STATUS) {
+ /* if a display interrupt */
+ u32 disp_irq;
+
+ disp_irq = RADEON_READ(R500_DISP_INTERRUPT_STATUS);
+
+ *r500_disp_int = disp_irq;
+ if (disp_irq & R500_D1_VBLANK_INTERRUPT)
+ RADEON_WRITE(R500_D1MODE_VBLANK_STATUS, R500_VBLANK_ACK);
+ if (disp_irq & R500_D2_VBLANK_INTERRUPT)
+ RADEON_WRITE(R500_D2MODE_VBLANK_STATUS, R500_VBLANK_ACK);
+ }
+ irq_mask |= R500_DISPLAY_INT_STATUS;
+ } else
+ irq_mask |= RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT;
+
+ irqs &= irq_mask;
+
if (irqs)
RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
+
return irqs;
}
@@ -68,44 +184,33 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
u32 stat;
+ u32 r500_disp_int;
/* Only consider the bits we're interested in - others could be used
* outside the DRM
*/
- stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
- RADEON_CRTC_VBLANK_STAT |
- RADEON_CRTC2_VBLANK_STAT));
+ stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int);
if (!stat)
return IRQ_NONE;
stat &= dev_priv->irq_enable_reg;
/* SW interrupt */
- if (stat & RADEON_SW_INT_TEST) {
+ if (stat & RADEON_SW_INT_TEST)
DRM_WAKEUP(&dev_priv->swi_queue);
- }
/* VBLANK interrupt */
- if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) {
- int vblank_crtc = dev_priv->vblank_crtc;
-
- if ((vblank_crtc &
- (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) ==
- (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
- if (stat & RADEON_CRTC_VBLANK_STAT)
- atomic_inc(&dev->vbl_received);
- if (stat & RADEON_CRTC2_VBLANK_STAT)
- atomic_inc(&dev->vbl_received2);
- } else if (((stat & RADEON_CRTC_VBLANK_STAT) &&
- (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) ||
- ((stat & RADEON_CRTC2_VBLANK_STAT) &&
- (vblank_crtc & DRM_RADEON_VBLANK_CRTC2)))
- atomic_inc(&dev->vbl_received);
-
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+ if (r500_disp_int & R500_D1_VBLANK_INTERRUPT)
+ drm_handle_vblank(dev, 0);
+ if (r500_disp_int & R500_D2_VBLANK_INTERRUPT)
+ drm_handle_vblank(dev, 1);
+ } else {
+ if (stat & RADEON_CRTC_VBLANK_STAT)
+ drm_handle_vblank(dev, 0);
+ if (stat & RADEON_CRTC2_VBLANK_STAT)
+ drm_handle_vblank(dev, 1);
}
-
return IRQ_HANDLED;
}
@@ -144,54 +249,31 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
return ret;
}
-static int radeon_driver_vblank_do_wait(struct drm_device * dev,
- unsigned int *sequence, int crtc)
+u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
{
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
- int ack = 0;
- atomic_t *counter;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
- if (crtc == DRM_RADEON_VBLANK_CRTC1) {
- counter = &dev->vbl_received;
- ack |= RADEON_CRTC_VBLANK_STAT;
- } else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
- counter = &dev->vbl_received2;
- ack |= RADEON_CRTC2_VBLANK_STAT;
- } else
+ if (crtc < 0 || crtc > 1) {
+ DRM_ERROR("Invalid crtc %d\n", crtc);
return -EINVAL;
+ }
- radeon_acknowledge_irqs(dev_priv, ack);
-
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(counter))
- - *sequence) <= (1 << 23)));
-
- *sequence = cur_vblank;
-
- return ret;
-}
-
-int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
-{
- return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1);
-}
-
-int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
-{
- return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2);
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+ if (crtc == 0)
+ return RADEON_READ(R500_D1CRTC_FRAME_COUNT);
+ else
+ return RADEON_READ(R500_D2CRTC_FRAME_COUNT);
+ } else {
+ if (crtc == 0)
+ return RADEON_READ(RADEON_CRTC_CRNT_FRAME);
+ else
+ return RADEON_READ(RADEON_CRTC2_CRNT_FRAME);
+ }
}
/* Needs the lock as it touches the ring.
@@ -234,46 +316,41 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr
return radeon_wait_irq(dev, irqwait->irq_seq);
}
-void radeon_enable_interrupt(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
-
- dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE;
- if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1)
- dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK;
-
- if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2)
- dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK;
-
- RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
- dev_priv->irq_enabled = 1;
-}
-
/* drm_dma.h hooks
*/
void radeon_driver_irq_preinstall(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
+ u32 dummy;
/* Disable *all* interrupts */
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+ RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
/* Clear bits if they're already high */
- radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
- RADEON_CRTC_VBLANK_STAT |
- RADEON_CRTC2_VBLANK_STAT));
+ radeon_acknowledge_irqs(dev_priv, &dummy);
}
-void radeon_driver_irq_postinstall(struct drm_device * dev)
+int radeon_driver_irq_postinstall(struct drm_device *dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
+ int ret;
atomic_set(&dev_priv->swi_emitted, 0);
DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
- radeon_enable_interrupt(dev);
+ ret = drm_vblank_init(dev, 2);
+ if (ret)
+ return ret;
+
+ dev->max_vblank_count = 0x001fffff;
+
+ radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
+
+ return 0;
}
void radeon_driver_irq_uninstall(struct drm_device * dev)
@@ -285,6 +362,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
dev_priv->irq_enabled = 0;
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+ RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
/* Disable *all* interrupts */
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
}
@@ -293,18 +372,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
int radeon_vblank_crtc_get(struct drm_device *dev)
{
drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
- u32 flag;
- u32 value;
-
- flag = RADEON_READ(RADEON_GEN_INT_CNTL);
- value = 0;
-
- if (flag & RADEON_CRTC_VBLANK_MASK)
- value |= DRM_RADEON_VBLANK_CRTC1;
- if (flag & RADEON_CRTC2_VBLANK_MASK)
- value |= DRM_RADEON_VBLANK_CRTC2;
- return value;
+ return dev_priv->vblank_crtc;
}
int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
@@ -315,6 +384,5 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
return -EINVAL;
}
dev_priv->vblank_crtc = (unsigned int)value;
- radeon_enable_interrupt(dev);
return 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c
index 11c146b4921..5d7153fcc7b 100644
--- a/drivers/gpu/drm/radeon/radeon_state.c
+++ b/drivers/gpu/drm/radeon/radeon_state.c
@@ -2997,7 +2997,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
value = GET_SCRATCH(2);
break;
case RADEON_PARAM_IRQ_NR:
- value = dev->irq;
+ value = drm_dev_to_irq(dev);
break;
case RADEON_PARAM_GART_BASE:
value = dev_priv->gart_vm_start;
diff --git a/drivers/gpu/drm/sis/sis_mm.c b/drivers/gpu/drm/sis/sis_mm.c
index b3878770fce..af22111397d 100644
--- a/drivers/gpu/drm/sis/sis_mm.c
+++ b/drivers/gpu/drm/sis/sis_mm.c
@@ -41,7 +41,7 @@
#define AGP_TYPE 1
-#if defined(CONFIG_FB_SIS)
+#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
/* fb management via fb device */
#define SIS_MM_ALIGN_SHIFT 0
@@ -57,7 +57,7 @@ static void *sis_sman_mm_allocate(void *private, unsigned long size,
if (req.size == 0)
return NULL;
else
- return (void *)~req.offset;
+ return (void *)(unsigned long)~req.offset;
}
static void sis_sman_mm_free(void *private, void *ref)
@@ -75,12 +75,12 @@ static unsigned long sis_sman_mm_offset(void *private, void *ref)
return ~((unsigned long)ref);
}
-#else /* CONFIG_FB_SIS */
+#else /* CONFIG_FB_SIS[_MODULE] */
#define SIS_MM_ALIGN_SHIFT 4
#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
-#endif /* CONFIG_FB_SIS */
+#endif /* CONFIG_FB_SIS[_MODULE] */
static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
@@ -89,7 +89,7 @@ static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file
int ret;
mutex_lock(&dev->struct_mutex);
-#if defined(CONFIG_FB_SIS)
+#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
{
struct drm_sman_mm sman_mm;
sman_mm.private = (void *)0xFFFFFFFF;
diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c
index 80c01cdfa37..0993b441fc4 100644
--- a/drivers/gpu/drm/via/via_drv.c
+++ b/drivers/gpu/drm/via/via_drv.c
@@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
- DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+ DRIVER_IRQ_SHARED,
.load = via_driver_load,
.unload = via_driver_unload,
.context_dtor = via_final_context,
- .vblank_wait = via_driver_vblank_wait,
+ .get_vblank_counter = via_get_vblank_counter,
+ .enable_vblank = via_enable_vblank,
+ .disable_vblank = via_disable_vblank,
.irq_preinstall = via_driver_irq_preinstall,
.irq_postinstall = via_driver_irq_postinstall,
.irq_uninstall = via_driver_irq_uninstall,
@@ -59,17 +61,17 @@ static struct drm_driver driver = {
.get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = via_ioctls,
.fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .ioctl = drm_ioctl,
- .mmap = drm_mmap,
- .poll = drm_poll,
- .fasync = drm_fasync,
- },
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .ioctl = drm_ioctl,
+ .mmap = drm_mmap,
+ .poll = drm_poll,
+ .fasync = drm_fasync,
+ },
.pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
},
.name = DRIVER_NAME,
diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h
index 2daae81874c..cafcb844a22 100644
--- a/drivers/gpu/drm/via/via_drv.h
+++ b/drivers/gpu/drm/via/via_drv.h
@@ -75,6 +75,7 @@ typedef struct drm_via_private {
struct timeval last_vblank;
int last_vblank_valid;
unsigned usec_per_vblank;
+ atomic_t vbl_received;
drm_via_state_t hc_state;
char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
@@ -130,21 +131,24 @@ extern int via_init_context(struct drm_device * dev, int context);
extern int via_final_context(struct drm_device * dev, int context);
extern int via_do_cleanup_map(struct drm_device * dev);
-extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
+extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
+extern int via_enable_vblank(struct drm_device *dev, int crtc);
+extern void via_disable_vblank(struct drm_device *dev, int crtc);
extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
extern void via_driver_irq_preinstall(struct drm_device * dev);
-extern void via_driver_irq_postinstall(struct drm_device * dev);
+extern int via_driver_irq_postinstall(struct drm_device *dev);
extern void via_driver_irq_uninstall(struct drm_device * dev);
extern int via_dma_cleanup(struct drm_device * dev);
extern void via_init_command_verifier(void);
extern int via_driver_dma_quiescent(struct drm_device * dev);
-extern void via_init_futex(drm_via_private_t * dev_priv);
-extern void via_cleanup_futex(drm_via_private_t * dev_priv);
-extern void via_release_futex(drm_via_private_t * dev_priv, int context);
+extern void via_init_futex(drm_via_private_t *dev_priv);
+extern void via_cleanup_futex(drm_via_private_t *dev_priv);
+extern void via_release_futex(drm_via_private_t *dev_priv, int context);
-extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv);
+extern void via_reclaim_buffers_locked(struct drm_device *dev,
+ struct drm_file *file_priv);
extern void via_lastclose(struct drm_device *dev);
extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c
index c6bb978a110..665d319b927 100644
--- a/drivers/gpu/drm/via/via_irq.c
+++ b/drivers/gpu/drm/via/via_irq.c
@@ -43,7 +43,7 @@
#define VIA_REG_INTERRUPT 0x200
/* VIA_REG_INTERRUPT */
-#define VIA_IRQ_GLOBAL (1 << 31)
+#define VIA_IRQ_GLOBAL (1 << 31)
#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
#define VIA_IRQ_VBLANK_PENDING (1 << 3)
#define VIA_IRQ_HQV0_ENABLE (1 << 11)
@@ -68,16 +68,15 @@
static maskarray_t via_pro_group_a_irqs[] = {
{VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
- 0x00000000},
+ 0x00000000 },
{VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
- 0x00000000},
+ 0x00000000 },
{VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
};
-static int via_num_pro_group_a =
- sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t);
+static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs);
static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
static maskarray_t via_unichrome_irqs[] = {
@@ -86,14 +85,24 @@ static maskarray_t via_unichrome_irqs[] = {
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
};
-static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t);
+static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs);
static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
+
static unsigned time_diff(struct timeval *now, struct timeval *then)
{
return (now->tv_usec >= then->tv_usec) ?
- now->tv_usec - then->tv_usec :
- 1000000 - (then->tv_usec - now->tv_usec);
+ now->tv_usec - then->tv_usec :
+ 1000000 - (then->tv_usec - now->tv_usec);
+}
+
+u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+ drm_via_private_t *dev_priv = dev->dev_private;
+ if (crtc != 0)
+ return 0;
+
+ return atomic_read(&dev_priv->vbl_received);
}
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
@@ -108,23 +117,22 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
status = VIA_READ(VIA_REG_INTERRUPT);
if (status & VIA_IRQ_VBLANK_PENDING) {
- atomic_inc(&dev->vbl_received);
- if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
+ atomic_inc(&dev_priv->vbl_received);
+ if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
do_gettimeofday(&cur_vblank);
if (dev_priv->last_vblank_valid) {
dev_priv->usec_per_vblank =
- time_diff(&cur_vblank,
- &dev_priv->last_vblank) >> 4;
+ time_diff(&cur_vblank,
+ &dev_priv->last_vblank) >> 4;
}
dev_priv->last_vblank = cur_vblank;
dev_priv->last_vblank_valid = 1;
}
- if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
+ if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
DRM_DEBUG("US per vblank is: %u\n",
dev_priv->usec_per_vblank);
}
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ drm_handle_vblank(dev, 0);
handled = 1;
}
@@ -145,6 +153,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
/* Acknowlege interrupts */
VIA_WRITE(VIA_REG_INTERRUPT, status);
+
if (handled)
return IRQ_HANDLED;
else
@@ -163,31 +172,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
}
}
-int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int via_enable_vblank(struct drm_device *dev, int crtc)
{
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
+ drm_via_private_t *dev_priv = dev->dev_private;
+ u32 status;
- DRM_DEBUG("\n");
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
+ if (crtc != 0) {
+ DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
return -EINVAL;
}
- viadrv_acknowledge_irqs(dev_priv);
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
+
+ VIA_WRITE8(0x83d4, 0x11);
+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
+ return 0;
+}
+
+void via_disable_vblank(struct drm_device *dev, int crtc)
+{
+ drm_via_private_t *dev_priv = dev->dev_private;
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received)) -
- *sequence) <= (1 << 23)));
+ VIA_WRITE8(0x83d4, 0x11);
+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
- *sequence = cur_vblank;
- return ret;
+ if (crtc != 0)
+ DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
}
static int
@@ -239,6 +251,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
return ret;
}
+
/*
* drm_dma.h hooks
*/
@@ -292,23 +305,25 @@ void via_driver_irq_preinstall(struct drm_device * dev)
}
}
-void via_driver_irq_postinstall(struct drm_device * dev)
+int via_driver_irq_postinstall(struct drm_device *dev)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
- DRM_DEBUG("\n");
- if (dev_priv) {
- status = VIA_READ(VIA_REG_INTERRUPT);
- VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
- | dev_priv->irq_enable_mask);
+ DRM_DEBUG("via_driver_irq_postinstall\n");
+ if (!dev_priv)
+ return -EINVAL;
- /* Some magic, oh for some data sheets ! */
+ drm_vblank_init(dev, 1);
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
+ | dev_priv->irq_enable_mask);
- VIA_WRITE8(0x83d4, 0x11);
- VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
+ /* Some magic, oh for some data sheets ! */
+ VIA_WRITE8(0x83d4, 0x11);
+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
- }
+ return 0;
}
void via_driver_irq_uninstall(struct drm_device * dev)
@@ -339,9 +354,6 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
drm_via_irq_t *cur_irq = dev_priv->via_irqs;
int force_sequence;
- if (!dev->irq)
- return -EINVAL;
-
if (irqwait->request.irq >= dev_priv->num_irqs) {
DRM_ERROR("Trying to wait on unknown irq %d\n",
irqwait->request.irq);
@@ -352,7 +364,8 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
case VIA_IRQ_RELATIVE:
- irqwait->request.sequence += atomic_read(&cur_irq->irq_received);
+ irqwait->request.sequence +=
+ atomic_read(&cur_irq->irq_received);
irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
case VIA_IRQ_ABSOLUTE:
break;
diff --git a/drivers/gpu/drm/via/via_mm.c b/drivers/gpu/drm/via/via_mm.c
index e64094916e4..f694cb5eded 100644
--- a/drivers/gpu/drm/via/via_mm.c
+++ b/drivers/gpu/drm/via/via_mm.c
@@ -93,8 +93,7 @@ int via_final_context(struct drm_device *dev, int context)
/* Last context, perform cleanup */
if (dev->ctx_count == 1 && dev->dev_private) {
DRM_DEBUG("Last Context\n");
- if (dev->irq)
- drm_irq_uninstall(dev);
+ drm_irq_uninstall(dev);
via_cleanup_futex(dev_priv);
via_do_cleanup_map(dev);
}
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 1d3b8a394d4..705a43cdeea 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -428,7 +428,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
if (!usbhid->out[usbhid->outhead].raw_report) {
spin_unlock_irqrestore(&usbhid->outlock, flags);
- warn("output queueing failed");
+ dev_warn(&hid->dev, "output queueing failed\n");
return;
}
hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
@@ -455,7 +455,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
- warn("control queueing failed");
+ dev_warn(&hid->dev, "control queueing failed\n");
return;
}
hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index b06b8e090a2..bc011da79e1 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -49,6 +49,9 @@
#define APPLESMC_MAX_DATA_LENGTH 32
+#define APPLESMC_MIN_WAIT 0x0040
+#define APPLESMC_MAX_WAIT 0x8000
+
#define APPLESMC_STATUS_MASK 0x0f
#define APPLESMC_READ_CMD 0x10
#define APPLESMC_WRITE_CMD 0x11
@@ -57,8 +60,8 @@
#define KEY_COUNT_KEY "#KEY" /* r-o ui32 */
-#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */
-#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */
+#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6-10 bytes) */
+#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6-10 bytes) */
#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
@@ -104,6 +107,15 @@ static const char* temperature_sensors_sets[][36] = {
/* Set 6: Macbook3 set */
{ "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H",
"Th0S", "Th1H", NULL },
+/* Set 7: Macbook Air */
+ { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP",
+ "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL },
+/* Set 8: Macbook Pro 4,1 (Penryn) */
+ { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H",
+ "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
+/* Set 9: Macbook Pro 3,1 (Santa Rosa) */
+ { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P",
+ "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
};
/* List of keys used to read/write fan speeds */
@@ -163,25 +175,25 @@ static unsigned int key_at_index;
static struct workqueue_struct *applesmc_led_wq;
/*
- * __wait_status - Wait up to 2ms for the status port to get a certain value
+ * __wait_status - Wait up to 32ms for the status port to get a certain value
* (masked with 0x0f), returning zero if the value is obtained. Callers must
* hold applesmc_lock.
*/
static int __wait_status(u8 val)
{
- unsigned int i;
+ int us;
val = val & APPLESMC_STATUS_MASK;
- for (i = 0; i < 200; i++) {
+ for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
+ udelay(us);
if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
if (debug)
printk(KERN_DEBUG
- "Waited %d us for status %x\n",
- i*10, val);
+ "Waited %d us for status %x\n",
+ 2 * us - APPLESMC_MIN_WAIT, val);
return 0;
}
- udelay(10);
}
printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
@@ -191,6 +203,25 @@ static int __wait_status(u8 val)
}
/*
+ * special treatment of command port - on newer macbooks, it seems necessary
+ * to resend the command byte before polling the status again. Callers must
+ * hold applesmc_lock.
+ */
+static int send_command(u8 cmd)
+{
+ int us;
+ for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
+ outb(cmd, APPLESMC_CMD_PORT);
+ udelay(us);
+ if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
+ return 0;
+ }
+ printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
+ cmd, inb(APPLESMC_CMD_PORT));
+ return -EIO;
+}
+
+/*
* applesmc_read_key - reads len bytes from a given key, and put them in buffer.
* Returns zero on success or a negative error on failure. Callers must
* hold applesmc_lock.
@@ -205,8 +236,7 @@ static int applesmc_read_key(const char* key, u8* buffer, u8 len)
return -EINVAL;
}
- outb(APPLESMC_READ_CMD, APPLESMC_CMD_PORT);
- if (__wait_status(0x0c))
+ if (send_command(APPLESMC_READ_CMD))
return -EIO;
for (i = 0; i < 4; i++) {
@@ -249,8 +279,7 @@ static int applesmc_write_key(const char* key, u8* buffer, u8 len)
return -EINVAL;
}
- outb(APPLESMC_WRITE_CMD, APPLESMC_CMD_PORT);
- if (__wait_status(0x0c))
+ if (send_command(APPLESMC_WRITE_CMD))
return -EIO;
for (i = 0; i < 4; i++) {
@@ -284,8 +313,7 @@ static int applesmc_get_key_at_index(int index, char* key)
readkey[2] = index >> 8;
readkey[3] = index;
- outb(APPLESMC_GET_KEY_BY_INDEX_CMD, APPLESMC_CMD_PORT);
- if (__wait_status(0x0c))
+ if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
return -EIO;
for (i = 0; i < 4; i++) {
@@ -315,8 +343,7 @@ static int applesmc_get_key_type(char* key, char* type)
{
int i;
- outb(APPLESMC_GET_KEY_TYPE_CMD, APPLESMC_CMD_PORT);
- if (__wait_status(0x0c))
+ if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
return -EIO;
for (i = 0; i < 4; i++) {
@@ -325,7 +352,7 @@ static int applesmc_get_key_type(char* key, char* type)
return -EIO;
}
- outb(5, APPLESMC_DATA_PORT);
+ outb(6, APPLESMC_DATA_PORT);
for (i = 0; i < 6; i++) {
if (__wait_status(0x05))
@@ -527,17 +554,27 @@ out:
static ssize_t applesmc_light_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
+ static int data_length;
int ret;
u8 left = 0, right = 0;
- u8 buffer[6];
+ u8 buffer[10], query[6];
mutex_lock(&applesmc_lock);
- ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, 6);
+ if (!data_length) {
+ ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
+ if (ret)
+ goto out;
+ data_length = clamp_val(query[0], 0, 10);
+ printk(KERN_INFO "applesmc: light sensor data length set to "
+ "%d\n", data_length);
+ }
+
+ ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
left = buffer[2];
if (ret)
goto out;
- ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, 6);
+ ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
right = buffer[2];
out:
@@ -1233,39 +1270,57 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = {
{ .accelerometer = 0, .light = 0, .temperature_set = 5 },
/* MacBook3: accelerometer and temperature set 6 */
{ .accelerometer = 1, .light = 0, .temperature_set = 6 },
+/* MacBook Air: accelerometer, backlight and temperature set 7 */
+ { .accelerometer = 1, .light = 1, .temperature_set = 7 },
+/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
+ { .accelerometer = 1, .light = 1, .temperature_set = 8 },
+/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
+ { .accelerometer = 1, .light = 1, .temperature_set = 9 },
};
/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
* So we need to put "Apple MacBook Pro" before "Apple MacBook". */
static __initdata struct dmi_system_id applesmc_whitelist[] = {
+ { applesmc_dmi_match, "Apple MacBook Air", {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
+ &applesmc_dmi_data[7]},
+ { applesmc_dmi_match, "Apple MacBook Pro 4", {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
+ &applesmc_dmi_data[8]},
+ { applesmc_dmi_match, "Apple MacBook Pro 3", {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
+ &applesmc_dmi_data[9]},
{ applesmc_dmi_match, "Apple MacBook Pro", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
- (void*)&applesmc_dmi_data[0]},
+ &applesmc_dmi_data[0]},
{ applesmc_dmi_match, "Apple MacBook (v2)", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
- (void*)&applesmc_dmi_data[1]},
+ &applesmc_dmi_data[1]},
{ applesmc_dmi_match, "Apple MacBook (v3)", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
- (void*)&applesmc_dmi_data[6]},
+ &applesmc_dmi_data[6]},
{ applesmc_dmi_match, "Apple MacBook", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
- (void*)&applesmc_dmi_data[2]},
+ &applesmc_dmi_data[2]},
{ applesmc_dmi_match, "Apple Macmini", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
- (void*)&applesmc_dmi_data[3]},
+ &applesmc_dmi_data[3]},
{ applesmc_dmi_match, "Apple MacPro2", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
- (void*)&applesmc_dmi_data[4]},
+ &applesmc_dmi_data[4]},
{ applesmc_dmi_match, "Apple iMac", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
- (void*)&applesmc_dmi_data[5]},
+ &applesmc_dmi_data[5]},
{ .ident = NULL }
};
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index 9b462bb13fa..5fbfa34c110 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -75,7 +75,8 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
#define FSCM 0x09 /* Logical device: fans */
#define VLM 0x0d /* Logical device: voltages */
#define TMS 0x0e /* Logical device: temperatures */
-static const u8 logdev[3] = { FSCM, VLM, TMS };
+#define LDNI_MAX 3
+static const u8 logdev[LDNI_MAX] = { FSCM, VLM, TMS };
#define LD_FAN 0
#define LD_IN 1
@@ -489,11 +490,66 @@ static struct sensor_device_attribute in_max[] = {
SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10),
};
+/* (temp & vin) channel status register alarm bits (pdf sec.11.5.12) */
+#define CHAN_ALM_MIN 0x02 /* min limit crossed */
+#define CHAN_ALM_MAX 0x04 /* max limit exceeded */
+#define TEMP_ALM_CRIT 0x08 /* temp crit exceeded (temp only) */
+
+/* show_in_min/max_alarm() reads data from the per-channel status
+ register (sec 11.5.12), not the vin event status registers (sec
+ 11.5.2) that (legacy) show_in_alarm() resds (via data->in_alarms) */
+
+static ssize_t show_in_min_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN));
+}
+static ssize_t show_in_max_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX));
+}
+
+static struct sensor_device_attribute in_min_alarm[] = {
+ SENSOR_ATTR(in0_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 0),
+ SENSOR_ATTR(in1_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 1),
+ SENSOR_ATTR(in2_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 2),
+ SENSOR_ATTR(in3_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 3),
+ SENSOR_ATTR(in4_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 4),
+ SENSOR_ATTR(in5_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 5),
+ SENSOR_ATTR(in6_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 6),
+ SENSOR_ATTR(in7_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 7),
+ SENSOR_ATTR(in8_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 8),
+ SENSOR_ATTR(in9_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 9),
+ SENSOR_ATTR(in10_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 10),
+};
+static struct sensor_device_attribute in_max_alarm[] = {
+ SENSOR_ATTR(in0_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 0),
+ SENSOR_ATTR(in1_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 1),
+ SENSOR_ATTR(in2_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 2),
+ SENSOR_ATTR(in3_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 3),
+ SENSOR_ATTR(in4_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 4),
+ SENSOR_ATTR(in5_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 5),
+ SENSOR_ATTR(in6_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 6),
+ SENSOR_ATTR(in7_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 7),
+ SENSOR_ATTR(in8_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 8),
+ SENSOR_ATTR(in9_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 9),
+ SENSOR_ATTR(in10_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 10),
+};
+
#define VIN_UNIT_ATTRS(X) \
&in_input[X].dev_attr.attr, \
&in_status[X].dev_attr.attr, \
&in_min[X].dev_attr.attr, \
- &in_max[X].dev_attr.attr
+ &in_max[X].dev_attr.attr, \
+ &in_min_alarm[X].dev_attr.attr, \
+ &in_max_alarm[X].dev_attr.attr
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -658,12 +714,68 @@ static struct sensor_device_attribute therm_crit[] = {
show_therm_crit, set_therm_crit, 2+11),
};
+/* show_therm_min/max_alarm() reads data from the per-channel voltage
+ status register (sec 11.5.12) */
+
+static ssize_t show_therm_min_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN));
+}
+static ssize_t show_therm_max_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX));
+}
+static ssize_t show_therm_crit_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%u\n", !!(data->in_status[nr] & TEMP_ALM_CRIT));
+}
+
+static struct sensor_device_attribute therm_min_alarm[] = {
+ SENSOR_ATTR(temp4_min_alarm, S_IRUGO,
+ show_therm_min_alarm, NULL, 0+11),
+ SENSOR_ATTR(temp5_min_alarm, S_IRUGO,
+ show_therm_min_alarm, NULL, 1+11),
+ SENSOR_ATTR(temp6_min_alarm, S_IRUGO,
+ show_therm_min_alarm, NULL, 2+11),
+};
+static struct sensor_device_attribute therm_max_alarm[] = {
+ SENSOR_ATTR(temp4_max_alarm, S_IRUGO,
+ show_therm_max_alarm, NULL, 0+11),
+ SENSOR_ATTR(temp5_max_alarm, S_IRUGO,
+ show_therm_max_alarm, NULL, 1+11),
+ SENSOR_ATTR(temp6_max_alarm, S_IRUGO,
+ show_therm_max_alarm, NULL, 2+11),
+};
+static struct sensor_device_attribute therm_crit_alarm[] = {
+ SENSOR_ATTR(temp4_crit_alarm, S_IRUGO,
+ show_therm_crit_alarm, NULL, 0+11),
+ SENSOR_ATTR(temp5_crit_alarm, S_IRUGO,
+ show_therm_crit_alarm, NULL, 1+11),
+ SENSOR_ATTR(temp6_crit_alarm, S_IRUGO,
+ show_therm_crit_alarm, NULL, 2+11),
+};
+
#define THERM_UNIT_ATTRS(X) \
&therm_input[X].dev_attr.attr, \
&therm_status[X].dev_attr.attr, \
&therm_min[X].dev_attr.attr, \
&therm_max[X].dev_attr.attr, \
- &therm_crit[X].dev_attr.attr
+ &therm_crit[X].dev_attr.attr, \
+ &therm_min_alarm[X].dev_attr.attr, \
+ &therm_max_alarm[X].dev_attr.attr, \
+ &therm_crit_alarm[X].dev_attr.attr
static struct attribute * pc8736x_therm_attr_array[] = {
THERM_UNIT_ATTRS(0),
@@ -790,12 +902,76 @@ static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *att
}
static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
+/* show_temp_min/max_alarm() reads data from the per-channel status
+ register (sec 12.3.7), not the temp event status registers (sec
+ 12.3.2) that show_temp_alarm() reads (via data->temp_alarms) */
+
+static ssize_t show_temp_min_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MIN));
+}
+static ssize_t show_temp_max_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MAX));
+}
+static ssize_t show_temp_crit_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_ALM_CRIT));
+}
+
+static struct sensor_device_attribute temp_min_alarm[] = {
+ SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 0),
+ SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 1),
+ SENSOR_ATTR(temp3_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 2),
+};
+static struct sensor_device_attribute temp_max_alarm[] = {
+ SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 0),
+ SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 1),
+ SENSOR_ATTR(temp3_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 2),
+};
+static struct sensor_device_attribute temp_crit_alarm[] = {
+ SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 0),
+ SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 1),
+ SENSOR_ATTR(temp3_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 2),
+};
+
+#define TEMP_FAULT 0x40 /* open diode */
+static ssize_t show_temp_fault(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ unsigned nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_FAULT));
+}
+static struct sensor_device_attribute temp_fault[] = {
+ SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0),
+ SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1),
+ SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2),
+};
+
#define TEMP_UNIT_ATTRS(X) \
&temp_input[X].dev_attr.attr, \
&temp_status[X].dev_attr.attr, \
&temp_min[X].dev_attr.attr, \
&temp_max[X].dev_attr.attr, \
- &temp_crit[X].dev_attr.attr
+ &temp_crit[X].dev_attr.attr, \
+ &temp_min_alarm[X].dev_attr.attr, \
+ &temp_max_alarm[X].dev_attr.attr, \
+ &temp_crit_alarm[X].dev_attr.attr, \
+ &temp_fault[X].dev_attr.attr
static struct attribute * pc8736x_temp_attr_array[] = {
TEMP_UNIT_ATTRS(0),
@@ -809,8 +985,8 @@ static const struct attribute_group pc8736x_temp_group = {
.attrs = pc8736x_temp_attr_array,
};
-static ssize_t show_name(struct device *dev, struct device_attribute
- *devattr, char *buf)
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
struct pc87360_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", data->name);
@@ -955,7 +1131,7 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
mutex_init(&data->update_lock);
platform_set_drvdata(pdev, data);
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < LDNI_MAX; i++) {
if (((data->address[i] = extra_isa[i]))
&& !request_region(extra_isa[i], PC87360_EXTENT,
pc87360_driver.driver.name)) {
@@ -1031,7 +1207,15 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&temp_crit[i].dev_attr))
|| (err = device_create_file(dev,
- &temp_status[i].dev_attr)))
+ &temp_status[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_min_alarm[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_max_alarm[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_crit_alarm[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_fault[i].dev_attr)))
goto ERROR3;
}
if ((err = device_create_file(dev, &dev_attr_alarms_temp)))
@@ -1131,6 +1315,16 @@ static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
mutex_unlock(&(data->lock));
}
+/* (temp & vin) channel conversion status register flags (pdf sec.11.5.12) */
+#define CHAN_CNVRTD 0x80 /* new data ready */
+#define CHAN_ENA 0x01 /* enabled channel (temp or vin) */
+#define CHAN_ALM_ENA 0x10 /* propagate to alarms-reg ?? (chk val!) */
+#define CHAN_READY (CHAN_ENA|CHAN_CNVRTD) /* sample ready mask */
+
+#define TEMP_OTS_OE 0x20 /* OTS Output Enable */
+#define VIN_RW1C_MASK (CHAN_READY|CHAN_ALM_MAX|CHAN_ALM_MIN) /* 0x87 */
+#define TEMP_RW1C_MASK (VIN_RW1C_MASK|TEMP_ALM_CRIT|TEMP_FAULT) /* 0xCF */
+
static void pc87360_init_device(struct platform_device *pdev,
int use_thermistors)
{
@@ -1152,11 +1346,12 @@ static void pc87360_init_device(struct platform_device *pdev,
nr = data->innr < 11 ? data->innr : 11;
for (i = 0; i < nr; i++) {
+ reg = pc87360_read_value(data, LD_IN, i,
+ PC87365_REG_IN_STATUS);
+ dev_dbg(&pdev->dev, "bios in%d status:0x%02x\n", i, reg);
if (init >= init_in[i]) {
/* Forcibly enable voltage channel */
- reg = pc87360_read_value(data, LD_IN, i,
- PC87365_REG_IN_STATUS);
- if (!(reg & 0x01)) {
+ if (!(reg & CHAN_ENA)) {
dev_dbg(&pdev->dev, "Forcibly "
"enabling in%d\n", i);
pc87360_write_value(data, LD_IN, i,
@@ -1168,19 +1363,24 @@ static void pc87360_init_device(struct platform_device *pdev,
/* We can't blindly trust the Super-I/O space configuration bit,
most BIOS won't set it properly */
+ dev_dbg(&pdev->dev, "bios thermistors:%d\n", use_thermistors);
for (i = 11; i < data->innr; i++) {
reg = pc87360_read_value(data, LD_IN, i,
PC87365_REG_TEMP_STATUS);
- use_thermistors = use_thermistors || (reg & 0x01);
+ use_thermistors = use_thermistors || (reg & CHAN_ENA);
+ /* thermistors are temp[4-6], measured on vin[11-14] */
+ dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i-7, reg);
}
+ dev_dbg(&pdev->dev, "using thermistors:%d\n", use_thermistors);
i = use_thermistors ? 2 : 0;
for (; i < data->tempnr; i++) {
+ reg = pc87360_read_value(data, LD_TEMP, i,
+ PC87365_REG_TEMP_STATUS);
+ dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i+1, reg);
if (init >= init_temp[i]) {
/* Forcibly enable temperature channel */
- reg = pc87360_read_value(data, LD_TEMP, i,
- PC87365_REG_TEMP_STATUS);
- if (!(reg & 0x01)) {
+ if (!(reg & CHAN_ENA)) {
dev_dbg(&pdev->dev, "Forcibly "
"enabling temp%d\n", i+1);
pc87360_write_value(data, LD_TEMP, i,
@@ -1197,7 +1397,7 @@ static void pc87360_init_device(struct platform_device *pdev,
diodes */
reg = pc87360_read_value(data, LD_TEMP,
(i-11)/2, PC87365_REG_TEMP_STATUS);
- if (reg & 0x01) {
+ if (reg & CHAN_ENA) {
dev_dbg(&pdev->dev, "Skipping "
"temp%d, pin already in use "
"by temp%d\n", i-7, (i-11)/2);
@@ -1207,7 +1407,7 @@ static void pc87360_init_device(struct platform_device *pdev,
/* Forcibly enable thermistor channel */
reg = pc87360_read_value(data, LD_IN, i,
PC87365_REG_IN_STATUS);
- if (!(reg & 0x01)) {
+ if (!(reg & CHAN_ENA)) {
dev_dbg(&pdev->dev, "Forcibly "
"enabling temp%d\n", i-7);
pc87360_write_value(data, LD_IN, i,
@@ -1221,7 +1421,8 @@ static void pc87360_init_device(struct platform_device *pdev,
if (data->innr) {
reg = pc87360_read_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONFIG);
- if (reg & 0x01) {
+ dev_dbg(&pdev->dev, "bios vin-cfg:0x%02x\n", reg);
+ if (reg & CHAN_ENA) {
dev_dbg(&pdev->dev, "Forcibly "
"enabling monitoring (VLM)\n");
pc87360_write_value(data, LD_IN, NO_BANK,
@@ -1233,7 +1434,8 @@ static void pc87360_init_device(struct platform_device *pdev,
if (data->tempnr) {
reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
PC87365_REG_TEMP_CONFIG);
- if (reg & 0x01) {
+ dev_dbg(&pdev->dev, "bios temp-cfg:0x%02x\n", reg);
+ if (reg & CHAN_ENA) {
dev_dbg(&pdev->dev, "Forcibly enabling "
"monitoring (TMS)\n");
pc87360_write_value(data, LD_TEMP, NO_BANK,
@@ -1336,11 +1538,11 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
pc87360_write_value(data, LD_IN, i,
PC87365_REG_IN_STATUS,
data->in_status[i]);
- if ((data->in_status[i] & 0x81) == 0x81) {
+ if ((data->in_status[i] & CHAN_READY) == CHAN_READY) {
data->in[i] = pc87360_read_value(data, LD_IN,
i, PC87365_REG_IN);
}
- if (data->in_status[i] & 0x01) {
+ if (data->in_status[i] & CHAN_ENA) {
data->in_min[i] = pc87360_read_value(data,
LD_IN, i,
PC87365_REG_IN_MIN);
@@ -1373,12 +1575,12 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
pc87360_write_value(data, LD_TEMP, i,
PC87365_REG_TEMP_STATUS,
data->temp_status[i]);
- if ((data->temp_status[i] & 0x81) == 0x81) {
+ if ((data->temp_status[i] & CHAN_READY) == CHAN_READY) {
data->temp[i] = pc87360_read_value(data,
LD_TEMP, i,
PC87365_REG_TEMP);
}
- if (data->temp_status[i] & 0x01) {
+ if (data->temp_status[i] & CHAN_ENA) {
data->temp_min[i] = pc87360_read_value(data,
LD_TEMP, i,
PC87365_REG_TEMP_MIN);
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 1e328d19cd6..3e01992230b 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -135,7 +135,7 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
*status = get_pcf(adap, 1);
#ifndef STUB_I2C
while (timeout-- && (*status & I2C_PCF_PIN)) {
- adap->waitforpin();
+ adap->waitforpin(adap->data);
*status = get_pcf(adap, 1);
}
if (*status & I2C_PCF_LAB) {
@@ -208,7 +208,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
return -ENXIO;
}
- printk(KERN_DEBUG "i2c-algo-pcf.o: deteted and initialized PCF8584.\n");
+ printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n");
return 0;
}
@@ -331,13 +331,16 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
int i;
int ret=0, timeout, status;
+ if (adap->xfer_begin)
+ adap->xfer_begin(adap->data);
/* Check for bus busy */
timeout = wait_for_bb(adap);
if (timeout) {
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
"Timeout waiting for BB in pcf_xfer\n");)
- return -EIO;
+ i = -EIO;
+ goto out;
}
for (i = 0;ret >= 0 && i < num; i++) {
@@ -359,12 +362,14 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
if (timeout) {
if (timeout == -EINTR) {
/* arbitration lost */
- return (-EINTR);
+ i = -EINTR;
+ goto out;
}
i2c_stop(adap);
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
"for PIN(1) in pcf_xfer\n");)
- return (-EREMOTEIO);
+ i = -EREMOTEIO;
+ goto out;
}
#ifndef STUB_I2C
@@ -372,7 +377,8 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
if (status & I2C_PCF_LRB) {
i2c_stop(adap);
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
- return (-EREMOTEIO);
+ i = -EREMOTEIO;
+ goto out;
}
#endif
@@ -404,6 +410,9 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
}
}
+out:
+ if (adap->xfer_end)
+ adap->xfer_end(adap->data);
return (i);
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index acadbc51fc0..7f95905bbb9 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -97,6 +97,7 @@ config I2C_I801
ICH9
Tolapai
ICH10
+ PCH
This driver can also be built as a module. If so, the module
will be called i2c-i801.
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 1ea39254dac..424dad6f18d 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -332,10 +332,6 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
int error;
u8 temp;
- /* driver_data might come from user-space, so check it */
- if (id->driver_data >= ARRAY_SIZE(chipname))
- return -EINVAL;
-
if (amd756_ioport) {
dev_err(&pdev->dev, "Only one device supported "
"(you have a strange motherboard, btw)\n");
@@ -412,7 +408,6 @@ static struct pci_driver amd756_driver = {
.id_table = amd756_ids,
.probe = amd756_probe,
.remove = __devexit_p(amd756_remove),
- .dynids.use_driver_data = 1,
};
static int __init amd756_init(void)
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index 8164de1f4d7..228f7572306 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -423,7 +423,6 @@ static const struct i2c_adapter cpm_ops = {
.owner = THIS_MODULE,
.name = "i2c-cpm",
.algo = &cpm_i2c_algo,
- .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
};
static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 7f38c01fb3a..0ed3ccb81b6 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -104,7 +104,8 @@ static int pcf_isa_getclock(void *data)
return (clock);
}
-static void pcf_isa_waitforpin(void) {
+static void pcf_isa_waitforpin(void *data)
+{
DEFINE_WAIT(wait);
int timeout = 2;
unsigned long flags;
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index 1098f21ace1..648aa7baff8 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -123,7 +123,7 @@ static int __devinit hydra_probe(struct pci_dev *dev,
hydra_adap.name))
return -EBUSY;
- hydra_bit_data.data = ioremap(base, pci_resource_len(dev, 0));
+ hydra_bit_data.data = pci_ioremap_bar(dev, 0);
if (hydra_bit_data.data == NULL) {
release_mem_region(base+offsetof(struct Hydra, CachePD), 4);
return -ENODEV;
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index dc7ea32b69a..5123eb69a97 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -41,6 +41,7 @@
Tolapai 0x5032 32 hard yes yes yes
ICH10 0x3a30 32 hard yes yes yes
ICH10 0x3a60 32 hard yes yes yes
+ PCH 0x3b30 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -576,6 +577,7 @@ static struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH_SMBUS) },
{ 0, }
};
@@ -599,6 +601,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
case PCI_DEVICE_ID_INTEL_ICH10_4:
case PCI_DEVICE_ID_INTEL_ICH10_5:
+ case PCI_DEVICE_ID_INTEL_PCH_SMBUS:
i801_features |= FEATURE_I2C_BLOCK_READ;
/* fall through */
case PCI_DEVICE_ID_INTEL_82801DB_3:
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 73dc52e114e..9f194d9efd9 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -332,10 +332,6 @@ static int __devinit vt596_probe(struct pci_dev *pdev,
unsigned char temp;
int error = -ENODEV;
- /* driver_data might come from user-space, so check it */
- if (id->driver_data & 1 || id->driver_data > 0xff)
- return -EINVAL;
-
/* Determine the address of the SMBus areas */
if (force_addr) {
vt596_smba = force_addr & 0xfff0;
@@ -483,7 +479,6 @@ static struct pci_driver vt596_driver = {
.name = "vt596_smbus",
.id_table = vt596_ids,
.probe = vt596_probe,
- .dynids.use_driver_data = 1,
};
static int __init i2c_vt596_init(void)
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 17356827b93..4c35702830c 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -1,6 +1,8 @@
#
# Miscellaneous I2C chip drivers configuration
#
+# *** DEPRECATED! Do not add new entries! See Makefile ***
+#
menu "Miscellaneous I2C Chip support"
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index ca520fa143d..23d2a31b0a6 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -1,7 +1,8 @@
#
# Makefile for miscellaneous I2C chip drivers.
#
-# Think twice before you add a new driver to this directory.
+# Do not add new drivers to this directory! It is DEPRECATED.
+#
# Device drivers are better grouped according to the functionality they
# implement rather than to the bus they are connected to. In particular:
# * Hardware monitoring chip drivers go to drivers/hwmon
diff --git a/drivers/i2c/chips/at24.c b/drivers/i2c/chips/at24.c
index 2a4acb26956..d4775528abc 100644
--- a/drivers/i2c/chips/at24.c
+++ b/drivers/i2c/chips/at24.c
@@ -460,7 +460,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
*/
at24->bin.attr.name = "eeprom";
at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
- at24->bin.attr.owner = THIS_MODULE;
at24->bin.read = at24_bin_read;
at24->bin.size = chip.byte_len;
diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c
index 23be4d42cb0..f3ee4a1abb7 100644
--- a/drivers/i2c/chips/ds1682.c
+++ b/drivers/i2c/chips/ds1682.c
@@ -190,7 +190,6 @@ static struct bin_attribute ds1682_eeprom_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = DS1682_EEPROM_SIZE,
.read = ds1682_eeprom_read,
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c
index 176126d3a01..4b364bae6b3 100644
--- a/drivers/i2c/chips/menelaus.c
+++ b/drivers/i2c/chips/menelaus.c
@@ -832,52 +832,52 @@ static irqreturn_t menelaus_irq(int irq, void *_menelaus)
static void menelaus_to_time(char *regs, struct rtc_time *t)
{
- t->tm_sec = BCD2BIN(regs[0]);
- t->tm_min = BCD2BIN(regs[1]);
+ t->tm_sec = bcd2bin(regs[0]);
+ t->tm_min = bcd2bin(regs[1]);
if (the_menelaus->rtc_control & RTC_CTRL_MODE12) {
- t->tm_hour = BCD2BIN(regs[2] & 0x1f) - 1;
+ t->tm_hour = bcd2bin(regs[2] & 0x1f) - 1;
if (regs[2] & RTC_HR_PM)
t->tm_hour += 12;
} else
- t->tm_hour = BCD2BIN(regs[2] & 0x3f);
- t->tm_mday = BCD2BIN(regs[3]);
- t->tm_mon = BCD2BIN(regs[4]) - 1;
- t->tm_year = BCD2BIN(regs[5]) + 100;
+ t->tm_hour = bcd2bin(regs[2] & 0x3f);
+ t->tm_mday = bcd2bin(regs[3]);
+ t->tm_mon = bcd2bin(regs[4]) - 1;
+ t->tm_year = bcd2bin(regs[5]) + 100;
}
static int time_to_menelaus(struct rtc_time *t, int regnum)
{
int hour, status;
- status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_sec));
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_sec));
if (status < 0)
goto fail;
- status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_min));
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_min));
if (status < 0)
goto fail;
if (the_menelaus->rtc_control & RTC_CTRL_MODE12) {
hour = t->tm_hour + 1;
if (hour > 12)
- hour = RTC_HR_PM | BIN2BCD(hour - 12);
+ hour = RTC_HR_PM | bin2bcd(hour - 12);
else
- hour = BIN2BCD(hour);
+ hour = bin2bcd(hour);
} else
- hour = BIN2BCD(t->tm_hour);
+ hour = bin2bcd(t->tm_hour);
status = menelaus_write_reg(regnum++, hour);
if (status < 0)
goto fail;
- status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_mday));
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mday));
if (status < 0)
goto fail;
- status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_mon + 1));
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mon + 1));
if (status < 0)
goto fail;
- status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_year - 100));
+ status = menelaus_write_reg(regnum++, bin2bcd(t->tm_year - 100));
if (status < 0)
goto fail;
@@ -914,7 +914,7 @@ static int menelaus_read_time(struct device *dev, struct rtc_time *t)
}
menelaus_to_time(regs, t);
- t->tm_wday = BCD2BIN(regs[6]);
+ t->tm_wday = bcd2bin(regs[6]);
return 0;
}
@@ -927,7 +927,7 @@ static int menelaus_set_time(struct device *dev, struct rtc_time *t)
status = time_to_menelaus(t, MENELAUS_RTC_SEC);
if (status < 0)
return status;
- status = menelaus_write_reg(MENELAUS_RTC_WKDAY, BIN2BCD(t->tm_wday));
+ status = menelaus_write_reg(MENELAUS_RTC_WKDAY, bin2bcd(t->tm_wday));
if (status < 0) {
dev_err(&the_menelaus->client->dev, "rtc write reg %02x "
"err %d\n", MENELAUS_RTC_WKDAY, status);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 42e852d79ff..5a485c22660 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -266,6 +266,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->dev.platform_data = info->platform_data;
+ if (info->archdata)
+ client->dev.archdata = *info->archdata;
+
client->flags = info->flags;
client->addr = info->addr;
client->irq = info->irq;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 74a369a6116..a820ca6fc32 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -84,21 +84,40 @@ config BLK_DEV_IDE_SATA
If unsure, say N.
-config BLK_DEV_IDEDISK
- tristate "Include IDE/ATA-2 DISK support"
- ---help---
- This will include enhanced support for MFM/RLL/IDE hard disks. If
- you have a MFM/RLL/IDE disk, and there is no special reason to use
- the old hard disk driver instead, say Y. If you have an SCSI-only
- system, you can say N here.
+config IDE_GD
+ tristate "generic ATA/ATAPI disk support"
+ default y
+ help
+ Support for ATA/ATAPI disks (including ATAPI floppy drives).
- To compile this driver as a module, choose M here: the
- module will be called ide-disk.
- Do not compile this driver as a module if your root file system
- (the one containing the directory /) is located on the IDE disk.
+ To compile this driver as a module, choose M here.
+ The module will be called ide-gd_mod.
+
+ If unsure, say Y.
+
+config IDE_GD_ATA
+ bool "ATA disk support"
+ depends on IDE_GD
+ default y
+ help
+ This will include support for ATA hard disks.
If unsure, say Y.
+config IDE_GD_ATAPI
+ bool "ATAPI floppy support"
+ depends on IDE_GD
+ select IDE_ATAPI
+ help
+ This will include support for ATAPI floppy drives
+ (i.e. Iomega ZIP or MKE LS-120).
+
+ For information about jumper settings and the question
+ of when a ZIP drive uses a partition table, see
+ <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>.
+
+ If unsure, say N.
+
config BLK_DEV_IDECS
tristate "PCMCIA IDE support"
depends on PCMCIA
@@ -163,29 +182,6 @@ config BLK_DEV_IDETAPE
To compile this driver as a module, choose M here: the
module will be called ide-tape.
-config BLK_DEV_IDEFLOPPY
- tristate "Include IDE/ATAPI FLOPPY support"
- select IDE_ATAPI
- ---help---
- If you have an IDE floppy drive which uses the ATAPI protocol,
- answer Y. ATAPI is a newer protocol used by IDE CD-ROM/tape/floppy
- drives, similar to the SCSI protocol.
-
- The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by
- this driver. For information about jumper settings and the question
- of when a ZIP drive uses a partition table, see
- <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>.
- (ATAPI PD-CD/CDR drives are not supported by this driver; support
- for PD-CD/CDR drives is available if you answer Y to
- "SCSI emulation support", below).
-
- If you say Y here, the FLOPPY drive will be identified along with
- other IDE devices, as "hdb" or "hdc", or something similar (check
- the boot messages with dmesg).
-
- To compile this driver as a module, choose M here: the
- module will be called ide-floppy.
-
config BLK_DEV_IDESCSI
tristate "SCSI emulation support (DEPRECATED)"
depends on SCSI
@@ -332,7 +328,7 @@ config IDEPCI_PCIBUS_ORDER
# TODO: split it on per host driver config options (or module parameters)
config BLK_DEV_OFFBOARD
bool "Boot off-board chipsets first support (DEPRECATED)"
- depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT34X || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001)
+ depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001)
help
Normally, IDE controllers built into the motherboard (on-board
controllers) are assigned to ide0 and ide1 while those on add-in PCI
@@ -482,28 +478,6 @@ config BLK_DEV_CS5535
It is safe to say Y to this question.
-config BLK_DEV_HPT34X
- tristate "HPT34X chipset support"
- depends on BROKEN
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds up to 4 more EIDE devices sharing a single
- interrupt. The HPT343 chipset in its current form is a non-bootable
- controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX)
- PCI UDMA controllers. This driver requires dynamic tuning of the
- chipset during the ide-probe at boot time. It is reported to support
- DVD II drives, by the manufacturer.
-
-config HPT34X_AUTODMA
- bool "HPT34X AUTODMA support (EXPERIMENTAL)"
- depends on BLK_DEV_HPT34X && EXPERIMENTAL
- help
- This is a dangerous thing to attempt currently! Please read the
- comments at the top of <file:drivers/ide/pci/hpt34x.c>. If you say Y
- here, then say Y to "Use DMA by default when available" as well.
-
- If unsure, say N.
-
config BLK_DEV_HPT366
tristate "HPT36X/37X chipset support"
select BLK_DEV_IDEDMA_PCI
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index ceaf779054e..9cf92ac939d 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -18,47 +18,96 @@ ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
obj-$(CONFIG_IDE) += ide-core.o
-ifeq ($(CONFIG_IDE_ARM), y)
- ide-arm-core-y += arm/ide_arm.o
- obj-y += ide-arm-core.o
-endif
+obj-$(CONFIG_IDE_ARM) += ide_arm.o
+
+obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o
+obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o
+obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o
+obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o
+obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o
+obj-$(CONFIG_BLK_DEV_4DRIVES) += ide-4drives.o
+
+obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o
+obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o
+obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o
+obj-$(CONFIG_BLK_DEV_Q40IDE) += q40ide.o
+obj-$(CONFIG_BLK_DEV_BUDDHA) += buddha.o
+
+obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o
+obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o
+obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o
+obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o
+obj-$(CONFIG_BLK_DEV_CELLEB) += scc_pata.o
+obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o
+obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o
+obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
+obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
+obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
+obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
+obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o
+obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
+obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o
+obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
+obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
+obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
+obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o
+obj-$(CONFIG_BLK_DEV_PIIX) += piix.o
+obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o
+obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o
+obj-$(CONFIG_BLK_DEV_SGIIOC4) += sgiioc4.o
+obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
+obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
+obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
+obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o
+obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o
+obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o
+obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
+obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
-obj-$(CONFIG_IDE) += legacy/ pci/
+# Must appear at the end of the block
+obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.o
+ide-pci-generic-y += generic.o
obj-$(CONFIG_IDEPCI_PCIBUS_ORDER) += ide-scan-pci.o
-ifeq ($(CONFIG_BLK_DEV_CMD640), y)
- cmd640-core-y += pci/cmd640.o
- obj-y += cmd640-core.o
-endif
+obj-$(CONFIG_BLK_DEV_CMD640) += cmd640.o
+
+obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o
+
+obj-$(CONFIG_IDE_H8300) += ide-h8300.o
-obj-$(CONFIG_IDE) += ppc/
-obj-$(CONFIG_IDE_H8300) += h8300/
obj-$(CONFIG_IDE_GENERIC) += ide-generic.o
obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
-ide-disk_mod-y += ide-disk.o ide-disk_ioctl.o
+ide-gd_mod-y += ide-gd.o
ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
-ide-floppy_mod-y += ide-floppy.o ide-floppy_ioctl.o
+ifeq ($(CONFIG_IDE_GD_ATA), y)
+ ide-gd_mod-y += ide-disk.o ide-disk_ioctl.o
ifeq ($(CONFIG_IDE_PROC_FS), y)
- ide-disk_mod-y += ide-disk_proc.o
- ide-floppy_mod-y += ide-floppy_proc.o
+ ide-gd_mod-y += ide-disk_proc.o
+endif
endif
-obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk_mod.o
+ifeq ($(CONFIG_IDE_GD_ATAPI), y)
+ ide-gd_mod-y += ide-floppy.o ide-floppy_ioctl.o
+ifeq ($(CONFIG_IDE_PROC_FS), y)
+ ide-gd_mod-y += ide-floppy_proc.o
+endif
+endif
+
+obj-$(CONFIG_IDE_GD) += ide-gd_mod.o
obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o
-obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy_mod.o
obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o
-ifeq ($(CONFIG_BLK_DEV_IDECS), y)
- ide-cs-core-y += legacy/ide-cs.o
- obj-y += ide-cs-core.o
-endif
+obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o
-ifeq ($(CONFIG_BLK_DEV_PLATFORM), y)
- ide-platform-core-y += legacy/ide_platform.o
- obj-y += ide-platform-core.o
-endif
+obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o
+
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o
+obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o
+obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o
-obj-$(CONFIG_IDE) += arm/ mips/
+obj-$(CONFIG_BLK_DEV_IDE_AU1XXX) += au1xxx-ide.o
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/aec62xx.c
index 4142c698e0d..4142c698e0d 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/aec62xx.c
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/ali14xx.c
index 90da1f953ed..90da1f953ed 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/ali14xx.c
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/alim15x3.c
index daf9dce39e5..daf9dce39e5 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/alim15x3.c
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/amd74xx.c
index 81ec73134ed..81ec73134ed 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/amd74xx.c
diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
deleted file mode 100644
index 5bc26053afa..00000000000
--- a/drivers/ide/arm/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-
-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o
-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o
-obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o
-
-ifeq ($(CONFIG_IDE_ARM), m)
- obj-m += ide_arm.o
-endif
-
-EXTRA_CFLAGS := -Idrivers/ide
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/atiixp.c
index b2735d28f5c..b2735d28f5c 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/atiixp.c
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c
index 0ec8fd1e4dc..0ec8fd1e4dc 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/au1xxx-ide.c
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/buddha.c
index c5a3c9ef6a5..c5a3c9ef6a5 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/buddha.c
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/cmd640.c
index e4306647d00..e4306647d00 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/cmd640.c
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/cmd64x.c
index 935385c77e0..935385c77e0 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/cmd64x.c
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/cs5520.c
index 5efb467f8fa..5efb467f8fa 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/cs5520.c
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/cs5530.c
index 53f079cc00a..53f079cc00a 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/cs5530.c
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/cs5535.c
index 983d957a018..983d957a018 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/cs5535.c
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/cy82c693.c
index 5297f07d293..5297f07d293 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/cy82c693.c
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/delkin_cb.c
index 8689a706f53..8f1b2d9f051 100644
--- a/drivers/ide/pci/delkin_cb.c
+++ b/drivers/ide/delkin_cb.c
@@ -46,10 +46,27 @@ static const struct ide_port_ops delkin_cb_port_ops = {
.quirkproc = ide_undecoded_slave,
};
+static unsigned int delkin_cb_init_chipset(struct pci_dev *dev)
+{
+ unsigned long base = pci_resource_start(dev, 0);
+ int i;
+
+ outb(0x02, base + 0x1e); /* set nIEN to block interrupts */
+ inb(base + 0x17); /* read status to clear interrupts */
+
+ for (i = 0; i < sizeof(setup); ++i) {
+ if (setup[i])
+ outb(setup[i], base + i);
+ }
+
+ return 0;
+}
+
static const struct ide_port_info delkin_cb_port_info = {
.port_ops = &delkin_cb_port_ops,
.host_flags = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS |
IDE_HFLAG_NO_DMA,
+ .init_chipset = delkin_cb_init_chipset,
};
static int __devinit
@@ -57,7 +74,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
struct ide_host *host;
unsigned long base;
- int i, rc;
+ int rc;
hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
rc = pci_enable_device(dev);
@@ -72,12 +89,8 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
return rc;
}
base = pci_resource_start(dev, 0);
- outb(0x02, base + 0x1e); /* set nIEN to block interrupts */
- inb(base + 0x17); /* read status to clear interrupts */
- for (i = 0; i < sizeof(setup); ++i) {
- if (setup[i])
- outb(setup[i], base + i);
- }
+
+ delkin_cb_init_chipset(dev);
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
@@ -110,6 +123,40 @@ delkin_cb_remove (struct pci_dev *dev)
pci_disable_device(dev);
}
+#ifdef CONFIG_PM
+static int delkin_cb_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ return 0;
+}
+
+static int delkin_cb_resume(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ int rc;
+
+ pci_set_power_state(dev, PCI_D0);
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ pci_restore_state(dev);
+ pci_set_master(dev);
+
+ if (host->init_chipset)
+ host->init_chipset(dev);
+
+ return 0;
+}
+#else
+#define delkin_cb_suspend NULL
+#define delkin_cb_resume NULL
+#endif
+
static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
{ 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -122,6 +169,8 @@ static struct pci_driver delkin_cb_pci_driver = {
.id_table = delkin_cb_pci_tbl,
.probe = delkin_cb_probe,
.remove = delkin_cb_remove,
+ .suspend = delkin_cb_suspend,
+ .resume = delkin_cb_resume,
};
static int __init delkin_cb_init(void)
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/dtc2278.c
index 689b2e49341..689b2e49341 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/dtc2278.c
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/falconide.c
index 39d500d84b0..39d500d84b0 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/falconide.c
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/gayle.c
index 69150688656..69150688656 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/gayle.c
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/generic.c
index 474f96a7c07..474f96a7c07 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/generic.c
diff --git a/drivers/ide/h8300/Makefile b/drivers/ide/h8300/Makefile
deleted file mode 100644
index 5eba16f423f..00000000000
--- a/drivers/ide/h8300/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-
-obj-$(CONFIG_IDE_H8300) += ide-h8300.o
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/hpt366.c
index 9cf171cb937..a7909e9c720 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -3,7 +3,7 @@
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
* Portions Copyright (C) 2007 Bartlomiej Zolnierkiewicz
- * Portions Copyright (C) 2005-2007 MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2008 MontaVista Software, Inc.
*
* Thanks to HighPoint Technologies for their assistance, and hardware.
* Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
@@ -748,26 +748,24 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
struct pci_dev *dev = to_pci_dev(hwif->dev);
struct hpt_info *info = hpt3xx_get_info(hwif->dev);
- if (drive->quirk_list) {
- if (info->chip_type >= HPT370) {
- u8 scr1 = 0;
-
- pci_read_config_byte(dev, 0x5a, &scr1);
- if (((scr1 & 0x10) >> 4) != mask) {
- if (mask)
- scr1 |= 0x10;
- else
- scr1 &= ~0x10;
- pci_write_config_byte(dev, 0x5a, scr1);
- }
- } else {
+ if (drive->quirk_list == 0)
+ return;
+
+ if (info->chip_type >= HPT370) {
+ u8 scr1 = 0;
+
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ if (((scr1 & 0x10) >> 4) != mask) {
if (mask)
- disable_irq(hwif->irq);
+ scr1 |= 0x10;
else
- enable_irq (hwif->irq);
+ scr1 &= ~0x10;
+ pci_write_config_byte(dev, 0x5a, scr1);
}
- } else
- outb(ATA_DEVCTL_OBS | (mask ? 2 : 0), hwif->io_ports.ctl_addr);
+ } else if (mask)
+ disable_irq(hwif->irq);
+ else
+ enable_irq(hwif->irq);
}
/*
@@ -1289,7 +1287,6 @@ static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
struct hpt_info *info = hpt3xx_get_info(hwif->dev);
int serialize = HPT_SERIALIZE_IO;
u8 chip_type = info->chip_type;
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/ht6560b.c
index c7e5c2246b7..c7e5c2246b7 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/ht6560b.c
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/icside.c
index 76bdc9a27f6..76bdc9a27f6 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/icside.c
diff --git a/drivers/ide/legacy/ide-4drives.c b/drivers/ide/ide-4drives.c
index 9e85b1ec960..9e85b1ec960 100644
--- a/drivers/ide/legacy/ide-4drives.c
+++ b/drivers/ide/ide-4drives.c
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index 2e305714c20..4e58b9e7a58 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -191,7 +191,7 @@ int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on)
{
struct ide_atapi_pc pc;
- if (drive->atapi_flags & IDE_AFLAG_NO_DOORLOCK)
+ if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
return 0;
ide_init_pc(&pc);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 3308b1cd3a3..133afd09843 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -99,7 +99,7 @@ static void ide_cd_put(struct cdrom_info *cd)
/* Mark that we've seen a media change and invalidate our internal buffers. */
static void cdrom_saw_media_change(ide_drive_t *drive)
{
- drive->atapi_flags |= IDE_AFLAG_MEDIA_CHANGED;
+ drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
}
@@ -340,8 +340,8 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
}
ide_debug_log(IDE_DBG_RQ, "%s: stat: 0x%x, good_stat: 0x%x, "
- "rq->cmd_type: 0x%x, err: 0x%x\n", __func__, stat,
- good_stat, rq->cmd_type, err);
+ "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x, err: 0x%x\n",
+ __func__, stat, good_stat, rq->cmd[0], rq->cmd_type, err);
if (blk_sense_request(rq)) {
/*
@@ -843,13 +843,10 @@ static void ide_cd_restore_request(ide_drive_t *drive, struct request *rq)
rq->q->prep_rq_fn(rq->q, rq);
}
-/*
- * All other packet commands.
- */
static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
{
-
- ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+ ide_debug_log(IDE_DBG_FUNC, "Call %s, rq->cmd[0]: 0x%x\n",
+ __func__, rq->cmd[0]);
/*
* Some of the trailing request sense fields are optional,
@@ -876,7 +873,7 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
if (!sense)
sense = &local_sense;
- ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x, "
+ ide_debug_log(IDE_DBG_PC, "Call %s, cmd[0]: 0x%x, write: 0x%x, "
"timeout: %d, cmd_flags: 0x%x\n", __func__, cmd[0], write,
timeout, cmd_flags);
@@ -1177,8 +1174,9 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
unsigned short sectors_per_frame =
queue_hardsect_size(drive->queue) >> SECTOR_BITS;
- ide_debug_log(IDE_DBG_RQ, "Call %s, write: 0x%x, secs_per_frame: %u\n",
- __func__, write, sectors_per_frame);
+ ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x, "
+ "secs_per_frame: %u\n",
+ __func__, rq->cmd[0], write, sectors_per_frame);
if (write) {
/* disk has become write protected */
@@ -1221,7 +1219,8 @@ static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive)
static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
{
- ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd_type: 0x%x\n", __func__,
+ ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, "
+ "rq->cmd_type: 0x%x\n", __func__, rq->cmd[0],
rq->cmd_type);
if (blk_pc_request(rq))
@@ -1257,9 +1256,6 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
}
}
-/*
- * cdrom driver request routine.
- */
static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
sector_t block)
{
@@ -1267,8 +1263,10 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
ide_handler_t *fn;
int xferlen;
- ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd_type: 0x%x, block: %llu\n",
- __func__, rq->cmd_type, (unsigned long long)block);
+ ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd[0]: 0x%x, "
+ "rq->cmd_type: 0x%x, block: %llu\n",
+ __func__, rq->cmd[0], rq->cmd_type,
+ (unsigned long long)block);
if (blk_fs_request(rq)) {
if (drive->atapi_flags & IDE_AFLAG_SEEKING) {
@@ -1412,6 +1410,10 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
*capacity = 1 + be32_to_cpu(capbuf.lba);
*sectors_per_frame = blocklen >> SECTOR_BITS;
+
+ ide_debug_log(IDE_DBG_PROBE, "%s: cap: %lu, sectors_per_frame: %lu\n",
+ __func__, *capacity, *sectors_per_frame);
+
return 0;
}
@@ -1643,6 +1645,9 @@ void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
maxspeed = be16_to_cpup((__be16 *)&buf[8 + 8]);
}
+ ide_debug_log(IDE_DBG_PROBE, "%s: curspeed: %u, maxspeed: %u\n",
+ __func__, curspeed, maxspeed);
+
cd->current_speed = (curspeed + (176/2)) / 176;
cd->max_speed = (maxspeed + (176/2)) / 176;
}
@@ -1732,7 +1737,7 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
return 0;
if ((buf[8 + 6] & 0x01) == 0)
- drive->atapi_flags |= IDE_AFLAG_NO_DOORLOCK;
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
if (buf[8 + 6] & 0x08)
drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT;
if (buf[8 + 3] & 0x01)
@@ -1777,7 +1782,7 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0)
printk(KERN_CONT " DVD%s%s",
(cdi->mask & CDC_DVD_R) ? "" : "-R",
- (cdi->mask & CDC_DVD_RAM) ? "" : "-RAM");
+ (cdi->mask & CDC_DVD_RAM) ? "" : "/RAM");
if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0)
printk(KERN_CONT " CD%s%s",
@@ -1908,6 +1913,16 @@ static const struct ide_proc_devset idecd_settings[] = {
IDE_PROC_DEVSET(dsc_overlap, 0, 1),
{ 0 },
};
+
+static ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive)
+{
+ return idecd_proc;
+}
+
+static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive)
+{
+ return idecd_settings;
+}
#endif
static const struct cd_list_entry ide_cd_quirks_list[] = {
@@ -1986,8 +2001,8 @@ static int ide_cdrom_setup(ide_drive_t *drive)
if (!drive->queue->unplug_delay)
drive->queue->unplug_delay = 1;
- drive->atapi_flags = IDE_AFLAG_MEDIA_CHANGED | IDE_AFLAG_NO_EJECT |
- ide_cd_flags(id);
+ drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
+ drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id);
if ((drive->atapi_flags & IDE_AFLAG_VERTOS_300_SSD) &&
fw_rev[4] == '1' && fw_rev[6] <= '2')
@@ -2069,22 +2084,20 @@ static ide_driver_t ide_cdrom_driver = {
.end_request = ide_end_request,
.error = __ide_error,
#ifdef CONFIG_IDE_PROC_FS
- .proc = idecd_proc,
- .settings = idecd_settings,
+ .proc_entries = ide_cd_proc_entries,
+ .proc_devsets = ide_cd_proc_devsets,
#endif
};
-static int idecd_open(struct inode *inode, struct file *file)
+static int idecd_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct cdrom_info *info;
+ struct cdrom_info *info = ide_cd_get(bdev->bd_disk);
int rc = -ENOMEM;
- info = ide_cd_get(disk);
if (!info)
return -ENXIO;
- rc = cdrom_open(&info->devinfo, inode, file);
+ rc = cdrom_open(&info->devinfo, bdev, mode);
if (rc < 0)
ide_cd_put(info);
@@ -2092,12 +2105,11 @@ static int idecd_open(struct inode *inode, struct file *file)
return rc;
}
-static int idecd_release(struct inode *inode, struct file *file)
+static int idecd_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
- cdrom_release(&info->devinfo, file);
+ cdrom_release(&info->devinfo, mode);
ide_cd_put(info);
@@ -2143,10 +2155,9 @@ static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
return 0;
}
-static int idecd_ioctl(struct inode *inode, struct file *file,
+static int idecd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
int err;
@@ -2159,9 +2170,9 @@ static int idecd_ioctl(struct inode *inode, struct file *file,
break;
}
- err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
+ err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
if (err == -EINVAL)
- err = cdrom_ioctl(file, &info->devinfo, inode, cmd, arg);
+ err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd, arg);
return err;
}
@@ -2186,7 +2197,7 @@ static struct block_device_operations idecd_ops = {
.owner = THIS_MODULE,
.open = idecd_open,
.release = idecd_release,
- .ioctl = idecd_ioctl,
+ .locked_ioctl = idecd_ioctl,
.media_changed = idecd_media_changed,
.revalidate_disk = idecd_revalidate_disk
};
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
index 74231b41f61..df3df0041eb 100644
--- a/drivers/ide/ide-cd_ioctl.c
+++ b/drivers/ide/ide-cd_ioctl.c
@@ -86,8 +86,8 @@ int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi,
if (slot_nr == CDSL_CURRENT) {
(void) cdrom_check_status(drive, NULL);
- retval = (drive->atapi_flags & IDE_AFLAG_MEDIA_CHANGED) ? 1 : 0;
- drive->atapi_flags &= ~IDE_AFLAG_MEDIA_CHANGED;
+ retval = (drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED) ? 1 : 0;
+ drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
return retval;
} else {
return -EINVAL;
@@ -136,7 +136,7 @@ int ide_cd_lockdoor(ide_drive_t *drive, int lockflag,
sense = &my_sense;
/* If the drive cannot lock the door, just pretend. */
- if (drive->atapi_flags & IDE_AFLAG_NO_DOORLOCK) {
+ if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) {
stat = 0;
} else {
unsigned char cmd[BLK_MAX_CDB];
@@ -157,7 +157,7 @@ int ide_cd_lockdoor(ide_drive_t *drive, int lockflag,
(sense->asc == 0x24 || sense->asc == 0x20)) {
printk(KERN_ERR "%s: door locking not supported\n",
drive->name);
- drive->atapi_flags |= IDE_AFLAG_NO_DOORLOCK;
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
stat = 0;
}
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/ide-cs.c
index cb199c815b5..cb199c815b5 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/ide-cs.c
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 3853bde8eed..223750c1b5a 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -14,9 +14,6 @@
* This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
*/
-#define IDEDISK_VERSION "1.18"
-
-#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -39,46 +36,8 @@
#include <asm/io.h>
#include <asm/div64.h>
-#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
-#define IDE_DISK_MINORS (1 << PARTN_BITS)
-#else
-#define IDE_DISK_MINORS 0
-#endif
-
#include "ide-disk.h"
-static DEFINE_MUTEX(idedisk_ref_mutex);
-
-#define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)
-
-static void ide_disk_release(struct kref *);
-
-static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
-{
- struct ide_disk_obj *idkp = NULL;
-
- mutex_lock(&idedisk_ref_mutex);
- idkp = ide_disk_g(disk);
- if (idkp) {
- if (ide_device_get(idkp->drive))
- idkp = NULL;
- else
- kref_get(&idkp->kref);
- }
- mutex_unlock(&idedisk_ref_mutex);
- return idkp;
-}
-
-static void ide_disk_put(struct ide_disk_obj *idkp)
-{
- ide_drive_t *drive = idkp->drive;
-
- mutex_lock(&idedisk_ref_mutex);
- kref_put(&idkp->kref, ide_disk_release);
- ide_device_put(drive);
- mutex_unlock(&idedisk_ref_mutex);
-}
-
static const u8 ide_rw_cmds[] = {
ATA_CMD_READ_MULTI,
ATA_CMD_WRITE_MULTI,
@@ -374,7 +333,7 @@ static void idedisk_check_hpa(ide_drive_t *drive)
}
}
-static void init_idedisk_capacity(ide_drive_t *drive)
+static int ide_disk_get_capacity(ide_drive_t *drive)
{
u16 *id = drive->id;
int lba;
@@ -403,11 +362,28 @@ static void init_idedisk_capacity(ide_drive_t *drive)
if (ata_id_hpa_enabled(id))
idedisk_check_hpa(drive);
}
-}
-sector_t ide_disk_capacity(ide_drive_t *drive)
-{
- return drive->capacity64;
+ /* limit drive capacity to 137GB if LBA48 cannot be used */
+ if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
+ drive->capacity64 > 1ULL << 28) {
+ printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
+ "%llu sectors (%llu MB)\n",
+ drive->name, (unsigned long long)drive->capacity64,
+ sectors_to_MB(drive->capacity64));
+ drive->capacity64 = 1ULL << 28;
+ }
+
+ if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
+ (drive->dev_flags & IDE_DFLAG_LBA48)) {
+ if (drive->capacity64 > 1ULL << 28) {
+ printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
+ " will be used for accessing sectors "
+ "> %u\n", drive->name, 1 << 28);
+ } else
+ drive->dev_flags &= ~IDE_DFLAG_LBA48;
+ }
+
+ return 0;
}
static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
@@ -508,7 +484,7 @@ static void update_ordered(ide_drive_t *drive)
* time we have trimmed the drive capacity if LBA48 is
* not available so we don't need to recheck that.
*/
- capacity = ide_disk_capacity(drive);
+ capacity = ide_gd_capacity(drive);
barrier = ata_id_flush_enabled(id) &&
(drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
@@ -616,7 +592,12 @@ ide_ext_devset_rw(wcache, wcache);
ide_ext_devset_rw_sync(nowerr, nowerr);
-static void idedisk_setup(ide_drive_t *drive)
+static int ide_disk_check(ide_drive_t *drive, const char *s)
+{
+ return 1;
+}
+
+static void ide_disk_setup(ide_drive_t *drive)
{
struct ide_disk_obj *idkp = drive->driver_data;
ide_hwif_t *hwif = drive->hwif;
@@ -652,33 +633,13 @@ static void idedisk_setup(ide_drive_t *drive)
drive->queue->max_sectors / 2);
/* calculate drive capacity, and select LBA if possible */
- init_idedisk_capacity(drive);
-
- /* limit drive capacity to 137GB if LBA48 cannot be used */
- if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
- drive->capacity64 > 1ULL << 28) {
- printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
- "%llu sectors (%llu MB)\n",
- drive->name, (unsigned long long)drive->capacity64,
- sectors_to_MB(drive->capacity64));
- drive->capacity64 = 1ULL << 28;
- }
-
- if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
- (drive->dev_flags & IDE_DFLAG_LBA48)) {
- if (drive->capacity64 > 1ULL << 28) {
- printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
- " will be used for accessing sectors "
- "> %u\n", drive->name, 1 << 28);
- } else
- drive->dev_flags &= ~IDE_DFLAG_LBA48;
- }
+ ide_disk_get_capacity(drive);
/*
* if possible, give fdisk access to more of the drive,
* by correcting bios_cyls:
*/
- capacity = ide_disk_capacity(drive);
+ capacity = ide_gd_capacity(drive);
if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
if (ata_id_lba48_enabled(drive->id)) {
@@ -718,9 +679,17 @@ static void idedisk_setup(ide_drive_t *drive)
drive->dev_flags |= IDE_DFLAG_WCACHE;
set_wcache(drive, 1);
+
+ if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
+ (drive->head == 0 || drive->head > 16)) {
+ printk(KERN_ERR "%s: invalid geometry: %d physical heads?\n",
+ drive->name, drive->head);
+ drive->dev_flags &= ~IDE_DFLAG_ATTACH;
+ } else
+ drive->dev_flags |= IDE_DFLAG_ATTACH;
}
-static void ide_cacheflush_p(ide_drive_t *drive)
+static void ide_disk_flush(ide_drive_t *drive)
{
if (ata_id_flush_enabled(drive->id) == 0 ||
(drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
@@ -730,267 +699,40 @@ static void ide_cacheflush_p(ide_drive_t *drive)
printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
}
-static void ide_disk_remove(ide_drive_t *drive)
-{
- struct ide_disk_obj *idkp = drive->driver_data;
- struct gendisk *g = idkp->disk;
-
- ide_proc_unregister_driver(drive, idkp->driver);
-
- del_gendisk(g);
-
- ide_cacheflush_p(drive);
-
- ide_disk_put(idkp);
-}
-
-static void ide_disk_release(struct kref *kref)
-{
- struct ide_disk_obj *idkp = to_ide_disk(kref);
- ide_drive_t *drive = idkp->drive;
- struct gendisk *g = idkp->disk;
-
- drive->driver_data = NULL;
- g->private_data = NULL;
- put_disk(g);
- kfree(idkp);
-}
-
-static int ide_disk_probe(ide_drive_t *drive);
-
-/*
- * On HPA drives the capacity needs to be
- * reinitilized on resume otherwise the disk
- * can not be used and a hard reset is required
- */
-static void ide_disk_resume(ide_drive_t *drive)
+static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk)
{
- if (ata_id_hpa_enabled(drive->id))
- init_idedisk_capacity(drive);
-}
-
-static void ide_device_shutdown(ide_drive_t *drive)
-{
-#ifdef CONFIG_ALPHA
- /* On Alpha, halt(8) doesn't actually turn the machine off,
- it puts you into the sort of firmware monitor. Typically,
- it's used to boot another kernel image, so it's not much
- different from reboot(8). Therefore, we don't need to
- spin down the disk in this case, especially since Alpha
- firmware doesn't handle disks in standby mode properly.
- On the other hand, it's reasonably safe to turn the power
- off when the shutdown process reaches the firmware prompt,
- as the firmware initialization takes rather long time -
- at least 10 seconds, which should be sufficient for
- the disk to expire its write cache. */
- if (system_state != SYSTEM_POWER_OFF) {
-#else
- if (system_state == SYSTEM_RESTART) {
-#endif
- ide_cacheflush_p(drive);
- return;
- }
-
- printk(KERN_INFO "Shutdown: %s\n", drive->name);
-
- drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
+ return 0;
}
-static ide_driver_t idedisk_driver = {
- .gen_driver = {
- .owner = THIS_MODULE,
- .name = "ide-disk",
- .bus = &ide_bus_type,
- },
- .probe = ide_disk_probe,
- .remove = ide_disk_remove,
- .resume = ide_disk_resume,
- .shutdown = ide_device_shutdown,
- .version = IDEDISK_VERSION,
- .do_request = ide_do_rw_disk,
- .end_request = ide_end_request,
- .error = __ide_error,
-#ifdef CONFIG_IDE_PROC_FS
- .proc = ide_disk_proc,
- .settings = ide_disk_settings,
-#endif
-};
-
-static int idedisk_set_doorlock(ide_drive_t *drive, int on)
+static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk,
+ int on)
{
ide_task_t task;
+ int ret;
+
+ if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
+ return 0;
memset(&task, 0, sizeof(task));
task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
- return ide_no_data_taskfile(drive, &task);
-}
-
-static int idedisk_open(struct inode *inode, struct file *filp)
-{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct ide_disk_obj *idkp;
- ide_drive_t *drive;
-
- idkp = ide_disk_get(disk);
- if (idkp == NULL)
- return -ENXIO;
-
- drive = idkp->drive;
-
- idkp->openers++;
-
- if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
- check_disk_change(inode->i_bdev);
- /*
- * Ignore the return code from door_lock,
- * since the open() has already succeeded,
- * and the door_lock is irrelevant at this point.
- */
- if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
- idedisk_set_doorlock(drive, 1))
- drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
- }
- return 0;
-}
-
-static int idedisk_release(struct inode *inode, struct file *filp)
-{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct ide_disk_obj *idkp = ide_disk_g(disk);
- ide_drive_t *drive = idkp->drive;
-
- if (idkp->openers == 1)
- ide_cacheflush_p(drive);
-
- if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
- if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
- idedisk_set_doorlock(drive, 0))
- drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
- }
+ ret = ide_no_data_taskfile(drive, &task);
- idkp->openers--;
+ if (ret)
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
- ide_disk_put(idkp);
-
- return 0;
-}
-
-static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
- ide_drive_t *drive = idkp->drive;
-
- geo->heads = drive->bios_head;
- geo->sectors = drive->bios_sect;
- geo->cylinders = (u16)drive->bios_cyl; /* truncate */
- return 0;
+ return ret;
}
-static int idedisk_media_changed(struct gendisk *disk)
-{
- struct ide_disk_obj *idkp = ide_disk_g(disk);
- ide_drive_t *drive = idkp->drive;
-
- /* do not scan partitions twice if this is a removable device */
- if (drive->dev_flags & IDE_DFLAG_ATTACH) {
- drive->dev_flags &= ~IDE_DFLAG_ATTACH;
- return 0;
- }
-
- /* if removable, always assume it was changed */
- return !!(drive->dev_flags & IDE_DFLAG_REMOVABLE);
-}
-
-static int idedisk_revalidate_disk(struct gendisk *disk)
-{
- struct ide_disk_obj *idkp = ide_disk_g(disk);
- set_capacity(disk, ide_disk_capacity(idkp->drive));
- return 0;
-}
-
-static struct block_device_operations idedisk_ops = {
- .owner = THIS_MODULE,
- .open = idedisk_open,
- .release = idedisk_release,
- .ioctl = ide_disk_ioctl,
- .getgeo = idedisk_getgeo,
- .media_changed = idedisk_media_changed,
- .revalidate_disk = idedisk_revalidate_disk
+const struct ide_disk_ops ide_ata_disk_ops = {
+ .check = ide_disk_check,
+ .get_capacity = ide_disk_get_capacity,
+ .setup = ide_disk_setup,
+ .flush = ide_disk_flush,
+ .init_media = ide_disk_init_media,
+ .set_doorlock = ide_disk_set_doorlock,
+ .do_request = ide_do_rw_disk,
+ .end_request = ide_end_request,
+ .ioctl = ide_disk_ioctl,
};
-
-MODULE_DESCRIPTION("ATA DISK Driver");
-
-static int ide_disk_probe(ide_drive_t *drive)
-{
- struct ide_disk_obj *idkp;
- struct gendisk *g;
-
- /* strstr("foo", "") is non-NULL */
- if (!strstr("ide-disk", drive->driver_req))
- goto failed;
-
- if (drive->media != ide_disk)
- goto failed;
-
- idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
- if (!idkp)
- goto failed;
-
- g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
- if (!g)
- goto out_free_idkp;
-
- ide_init_disk(g, drive);
-
- kref_init(&idkp->kref);
-
- idkp->drive = drive;
- idkp->driver = &idedisk_driver;
- idkp->disk = g;
-
- g->private_data = &idkp->driver;
-
- drive->driver_data = idkp;
-
- idedisk_setup(drive);
- if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
- (drive->head == 0 || drive->head > 16)) {
- printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
- drive->name, drive->head);
- drive->dev_flags &= ~IDE_DFLAG_ATTACH;
- } else
- drive->dev_flags |= IDE_DFLAG_ATTACH;
-
- g->minors = IDE_DISK_MINORS;
- g->driverfs_dev = &drive->gendev;
- g->flags |= GENHD_FL_EXT_DEVT;
- if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
- g->flags = GENHD_FL_REMOVABLE;
- set_capacity(g, ide_disk_capacity(drive));
- g->fops = &idedisk_ops;
- add_disk(g);
- return 0;
-
-out_free_idkp:
- kfree(idkp);
-failed:
- return -ENODEV;
-}
-
-static void __exit idedisk_exit(void)
-{
- driver_unregister(&idedisk_driver.gen_driver);
-}
-
-static int __init idedisk_init(void)
-{
- return driver_register(&idedisk_driver.gen_driver);
-}
-
-MODULE_ALIAS("ide:*m-disk*");
-MODULE_ALIAS("ide-disk");
-module_init(idedisk_init);
-module_exit(idedisk_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-disk.h b/drivers/ide/ide-disk.h
index a82fa435566..d511dab7c4a 100644
--- a/drivers/ide/ide-disk.h
+++ b/drivers/ide/ide-disk.h
@@ -1,19 +1,11 @@
#ifndef __IDE_DISK_H
#define __IDE_DISK_H
-struct ide_disk_obj {
- ide_drive_t *drive;
- ide_driver_t *driver;
- struct gendisk *disk;
- struct kref kref;
- unsigned int openers; /* protected by BKL for now */
-};
-
-#define ide_disk_g(disk) \
- container_of((disk)->private_data, struct ide_disk_obj, driver)
+#include "ide-gd.h"
+#ifdef CONFIG_IDE_GD_ATA
/* ide-disk.c */
-sector_t ide_disk_capacity(ide_drive_t *);
+extern const struct ide_disk_ops ide_ata_disk_ops;
ide_decl_devset(address);
ide_decl_devset(multcount);
ide_decl_devset(nowerr);
@@ -21,12 +13,17 @@ ide_decl_devset(wcache);
ide_decl_devset(acoustic);
/* ide-disk_ioctl.c */
-int ide_disk_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+int ide_disk_ioctl(ide_drive_t *, struct block_device *, fmode_t, unsigned int,
+ unsigned long);
#ifdef CONFIG_IDE_PROC_FS
/* ide-disk_proc.c */
extern ide_proc_entry_t ide_disk_proc[];
extern const struct ide_proc_devset ide_disk_settings[];
#endif
+#else
+#define ide_disk_proc NULL
+#define ide_disk_settings NULL
+#endif
#endif /* __IDE_DISK_H */
diff --git a/drivers/ide/ide-disk_ioctl.c b/drivers/ide/ide-disk_ioctl.c
index a6cf1a03a80..7b783dd7c0b 100644
--- a/drivers/ide/ide-disk_ioctl.c
+++ b/drivers/ide/ide-disk_ioctl.c
@@ -13,17 +13,14 @@ static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
{ 0 }
};
-int ide_disk_ioctl(struct inode *inode, struct file *file,
+int ide_disk_ioctl(ide_drive_t *drive, struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
- struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
- ide_drive_t *drive = idkp->drive;
int err;
err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
if (err != -EOPNOTSUPP)
return err;
- return generic_ide_ioctl(drive, file, bdev, cmd, arg);
+ return generic_ide_ioctl(drive, bdev, cmd, arg);
}
diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c
index 4724976afe7..1146f4204c6 100644
--- a/drivers/ide/ide-disk_proc.c
+++ b/drivers/ide/ide-disk_proc.c
@@ -56,7 +56,7 @@ static int proc_idedisk_read_capacity
ide_drive_t*drive = (ide_drive_t *)data;
int len;
- len = sprintf(page, "%llu\n", (long long)ide_disk_capacity(drive));
+ len = sprintf(page, "%llu\n", (long long)ide_gd_capacity(drive));
PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c
index 0903782689e..cac431f0df1 100644
--- a/drivers/ide/ide-dma-sff.c
+++ b/drivers/ide/ide-dma-sff.c
@@ -130,7 +130,7 @@ int ide_build_dmatable(ide_drive_t *drive, struct request *rq)
xcount = bcount & 0xffff;
if (is_trm290)
xcount = ((xcount >> 2) - 1) << 16;
- if (xcount == 0x0000) {
+ else if (xcount == 0x0000) {
if (count++ >= PRD_ENTRIES)
goto use_pio_instead;
*table++ = cpu_to_le32(0x8000);
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index cf0aa25470e..aeb1ad782f5 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -15,12 +15,6 @@
* Documentation/ide/ChangeLog.ide-floppy.1996-2002
*/
-#define DRV_NAME "ide-floppy"
-#define PFX DRV_NAME ": "
-
-#define IDEFLOPPY_VERSION "1.00"
-
-#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -49,19 +43,6 @@
#include "ide-floppy.h"
-/* module parameters */
-static unsigned long debug_mask;
-module_param(debug_mask, ulong, 0644);
-
-/* define to see debug info */
-#define IDEFLOPPY_DEBUG_LOG 0
-
-#if IDEFLOPPY_DEBUG_LOG
-#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
-#else
-#define ide_debug_log(lvl, fmt, args...) do {} while (0)
-#endif
-
/*
* After each failed packet command we issue a request sense command and retry
* the packet command IDEFLOPPY_MAX_PC_RETRIES times.
@@ -83,43 +64,13 @@ module_param(debug_mask, ulong, 0644);
/* Error code returned in rq->errors to the higher part of the driver. */
#define IDEFLOPPY_ERROR_GENERAL 101
-static DEFINE_MUTEX(idefloppy_ref_mutex);
-
-static void idefloppy_cleanup_obj(struct kref *);
-
-static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
-{
- struct ide_floppy_obj *floppy = NULL;
-
- mutex_lock(&idefloppy_ref_mutex);
- floppy = ide_drv_g(disk, ide_floppy_obj);
- if (floppy) {
- if (ide_device_get(floppy->drive))
- floppy = NULL;
- else
- kref_get(&floppy->kref);
- }
- mutex_unlock(&idefloppy_ref_mutex);
- return floppy;
-}
-
-static void ide_floppy_put(struct ide_floppy_obj *floppy)
-{
- ide_drive_t *drive = floppy->drive;
-
- mutex_lock(&idefloppy_ref_mutex);
- kref_put(&floppy->kref, idefloppy_cleanup_obj);
- ide_device_put(drive);
- mutex_unlock(&idefloppy_ref_mutex);
-}
-
/*
* Used to finish servicing a request. For read/write requests, we will call
* ide_end_request to pass to the next buffer.
*/
-static int idefloppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
+static int ide_floppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
struct request *rq = HWGROUP(drive)->rq;
int error;
@@ -161,12 +112,12 @@ static void idefloppy_update_buffers(ide_drive_t *drive,
struct bio *bio = rq->bio;
while ((bio = rq->bio) != NULL)
- idefloppy_end_request(drive, 1, 0);
+ ide_floppy_end_request(drive, 1, 0);
}
static void ide_floppy_callback(ide_drive_t *drive, int dsc)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
struct ide_atapi_pc *pc = drive->pc;
int uptodate = pc->error ? 0 : 1;
@@ -200,10 +151,10 @@ static void ide_floppy_callback(ide_drive_t *drive, int dsc)
"Aborting request!\n");
}
- idefloppy_end_request(drive, uptodate, 0);
+ ide_floppy_end_request(drive, uptodate, 0);
}
-static void ide_floppy_report_error(idefloppy_floppy_t *floppy,
+static void ide_floppy_report_error(struct ide_disk_obj *floppy,
struct ide_atapi_pc *pc)
{
/* supress error messages resulting from Medium not present */
@@ -222,7 +173,7 @@ static void ide_floppy_report_error(idefloppy_floppy_t *floppy,
static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
struct ide_atapi_pc *pc)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
if (floppy->failed_pc == NULL &&
pc->c[0] != GPCMD_REQUEST_SENSE)
@@ -286,7 +237,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive,
struct ide_atapi_pc *pc, struct request *rq,
unsigned long sector)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
int block = sector / floppy->bs_factor;
int blocks = rq->nr_sectors / floppy->bs_factor;
int cmd = rq_data_dir(rq);
@@ -310,7 +261,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive,
pc->flags |= PC_FLAG_DMA_OK;
}
-static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy,
+static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy,
struct ide_atapi_pc *pc, struct request *rq)
{
ide_init_pc(pc);
@@ -329,13 +280,12 @@ static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy,
pc->req_xfer = pc->buf_size = rq->data_len;
}
-static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
- struct request *rq, sector_t block_s)
+static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
+ struct request *rq, sector_t block)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
ide_hwif_t *hwif = drive->hwif;
struct ide_atapi_pc *pc;
- unsigned long block = (unsigned long)block_s;
ide_debug_log(IDE_DBG_FUNC, "%s: dev: %s, cmd: 0x%x, cmd_type: %x, "
"errors: %d\n",
@@ -353,7 +303,7 @@ static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
else
printk(KERN_ERR PFX "%s: I/O error\n", drive->name);
- idefloppy_end_request(drive, 0, 0);
+ ide_floppy_end_request(drive, 0, 0);
return ide_stopped;
}
if (blk_fs_request(rq)) {
@@ -361,11 +311,11 @@ static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
(rq->nr_sectors % floppy->bs_factor)) {
printk(KERN_ERR PFX "%s: unsupported r/w rq size\n",
drive->name);
- idefloppy_end_request(drive, 0, 0);
+ ide_floppy_end_request(drive, 0, 0);
return ide_stopped;
}
pc = &floppy->queued_pc;
- idefloppy_create_rw_cmd(drive, pc, rq, block);
+ idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block);
} else if (blk_special_request(rq)) {
pc = (struct ide_atapi_pc *) rq->buffer;
} else if (blk_pc_request(rq)) {
@@ -373,7 +323,7 @@ static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
idefloppy_blockpc_cmd(floppy, pc, rq);
} else {
blk_dump_rq_flags(rq, PFX "unsupported command in queue");
- idefloppy_end_request(drive, 0, 0);
+ ide_floppy_end_request(drive, 0, 0);
return ide_stopped;
}
@@ -394,7 +344,7 @@ static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
*/
static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
struct gendisk *disk = floppy->disk;
struct ide_atapi_pc pc;
u8 *page;
@@ -410,11 +360,11 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
}
if (pc.buf[3] & 0x80)
- drive->atapi_flags |= IDE_AFLAG_WP;
+ drive->dev_flags |= IDE_DFLAG_WP;
else
- drive->atapi_flags &= ~IDE_AFLAG_WP;
+ drive->dev_flags &= ~IDE_DFLAG_WP;
- set_disk_ro(disk, !!(drive->atapi_flags & IDE_AFLAG_WP));
+ set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP));
page = &pc.buf[8];
@@ -445,7 +395,9 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
drive->name, lba_capacity, capacity);
floppy->blocks = floppy->block_size ?
capacity / floppy->block_size : 0;
+ drive->capacity64 = floppy->blocks * floppy->bs_factor;
}
+
return 0;
}
@@ -455,7 +407,7 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
*/
static int ide_floppy_get_capacity(ide_drive_t *drive)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
struct gendisk *disk = floppy->disk;
struct ide_atapi_pc pc;
u8 *cap_desc;
@@ -466,7 +418,7 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
drive->bios_head = drive->bios_sect = 0;
floppy->blocks = 0;
floppy->bs_factor = 1;
- set_capacity(floppy->disk, 0);
+ drive->capacity64 = 0;
ide_floppy_create_read_capacity_cmd(&pc);
if (ide_queue_pc_tail(drive, disk, &pc)) {
@@ -523,6 +475,8 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
"non 512 bytes block size not "
"fully supported\n",
drive->name);
+ drive->capacity64 =
+ floppy->blocks * floppy->bs_factor;
rc = 0;
}
break;
@@ -547,21 +501,12 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
(void) ide_floppy_get_flexible_disk_page(drive);
- set_capacity(disk, floppy->blocks * floppy->bs_factor);
-
return rc;
}
-sector_t ide_floppy_capacity(ide_drive_t *drive)
-{
- idefloppy_floppy_t *floppy = drive->driver_data;
- unsigned long capacity = floppy->blocks * floppy->bs_factor;
-
- return capacity;
-}
-
-static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
+static void ide_floppy_setup(ide_drive_t *drive)
{
+ struct ide_disk_obj *floppy = drive->driver_data;
u16 *id = drive->id;
drive->pc_callback = ide_floppy_callback;
@@ -592,252 +537,42 @@ static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
blk_queue_max_sectors(drive->queue, 64);
drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE;
/* IOMEGA Clik! drives do not support lock/unlock commands */
- drive->atapi_flags |= IDE_AFLAG_NO_DOORLOCK;
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
}
(void) ide_floppy_get_capacity(drive);
ide_proc_register_driver(drive, floppy->driver);
-}
-static void ide_floppy_remove(ide_drive_t *drive)
-{
- idefloppy_floppy_t *floppy = drive->driver_data;
- struct gendisk *g = floppy->disk;
-
- ide_proc_unregister_driver(drive, floppy->driver);
-
- del_gendisk(g);
-
- ide_floppy_put(floppy);
+ drive->dev_flags |= IDE_DFLAG_ATTACH;
}
-static void idefloppy_cleanup_obj(struct kref *kref)
+static void ide_floppy_flush(ide_drive_t *drive)
{
- struct ide_floppy_obj *floppy = to_ide_drv(kref, ide_floppy_obj);
- ide_drive_t *drive = floppy->drive;
- struct gendisk *g = floppy->disk;
-
- drive->driver_data = NULL;
- g->private_data = NULL;
- put_disk(g);
- kfree(floppy);
}
-static int ide_floppy_probe(ide_drive_t *);
-
-static ide_driver_t idefloppy_driver = {
- .gen_driver = {
- .owner = THIS_MODULE,
- .name = "ide-floppy",
- .bus = &ide_bus_type,
- },
- .probe = ide_floppy_probe,
- .remove = ide_floppy_remove,
- .version = IDEFLOPPY_VERSION,
- .do_request = idefloppy_do_request,
- .end_request = idefloppy_end_request,
- .error = __ide_error,
-#ifdef CONFIG_IDE_PROC_FS
- .proc = ide_floppy_proc,
- .settings = ide_floppy_settings,
-#endif
-};
-
-static int idefloppy_open(struct inode *inode, struct file *filp)
+static int ide_floppy_init_media(ide_drive_t *drive, struct gendisk *disk)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct ide_floppy_obj *floppy;
- ide_drive_t *drive;
int ret = 0;
- floppy = ide_floppy_get(disk);
- if (!floppy)
- return -ENXIO;
-
- drive = floppy->drive;
-
- ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
-
- floppy->openers++;
-
- if (floppy->openers == 1) {
- drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
- /* Just in case */
-
- if (ide_do_test_unit_ready(drive, disk))
- ide_do_start_stop(drive, disk, 1);
-
- if (ide_floppy_get_capacity(drive)
- && (filp->f_flags & O_NDELAY) == 0
- /*
- * Allow O_NDELAY to open a drive without a disk, or with an
- * unreadable disk, so that we can get the format capacity
- * of the drive or begin the format - Sam
- */
- ) {
- ret = -EIO;
- goto out_put_floppy;
- }
-
- if ((drive->atapi_flags & IDE_AFLAG_WP) && (filp->f_mode & 2)) {
- ret = -EROFS;
- goto out_put_floppy;
- }
-
- drive->atapi_flags |= IDE_AFLAG_MEDIA_CHANGED;
- ide_set_media_lock(drive, disk, 1);
- check_disk_change(inode->i_bdev);
- } else if (drive->atapi_flags & IDE_AFLAG_FORMAT_IN_PROGRESS) {
- ret = -EBUSY;
- goto out_put_floppy;
- }
- return 0;
-
-out_put_floppy:
- floppy->openers--;
- ide_floppy_put(floppy);
- return ret;
-}
-
-static int idefloppy_release(struct inode *inode, struct file *filp)
-{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
- ide_drive_t *drive = floppy->drive;
-
- ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
-
- if (floppy->openers == 1) {
- ide_set_media_lock(drive, disk, 0);
- drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
- }
-
- floppy->openers--;
-
- ide_floppy_put(floppy);
-
- return 0;
-}
-
-static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct ide_floppy_obj *floppy = ide_drv_g(bdev->bd_disk,
- ide_floppy_obj);
- ide_drive_t *drive = floppy->drive;
+ if (ide_do_test_unit_ready(drive, disk))
+ ide_do_start_stop(drive, disk, 1);
- geo->heads = drive->bios_head;
- geo->sectors = drive->bios_sect;
- geo->cylinders = (u16)drive->bios_cyl; /* truncate */
- return 0;
-}
+ ret = ide_floppy_get_capacity(drive);
-static int idefloppy_media_changed(struct gendisk *disk)
-{
- struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
- ide_drive_t *drive = floppy->drive;
- int ret;
+ set_capacity(disk, ide_gd_capacity(drive));
- /* do not scan partitions twice if this is a removable device */
- if (drive->dev_flags & IDE_DFLAG_ATTACH) {
- drive->dev_flags &= ~IDE_DFLAG_ATTACH;
- return 0;
- }
- ret = !!(drive->atapi_flags & IDE_AFLAG_MEDIA_CHANGED);
- drive->atapi_flags &= ~IDE_AFLAG_MEDIA_CHANGED;
return ret;
}
-static int idefloppy_revalidate_disk(struct gendisk *disk)
-{
- struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
- set_capacity(disk, ide_floppy_capacity(floppy->drive));
- return 0;
-}
-
-static struct block_device_operations idefloppy_ops = {
- .owner = THIS_MODULE,
- .open = idefloppy_open,
- .release = idefloppy_release,
- .ioctl = ide_floppy_ioctl,
- .getgeo = idefloppy_getgeo,
- .media_changed = idefloppy_media_changed,
- .revalidate_disk = idefloppy_revalidate_disk
+const struct ide_disk_ops ide_atapi_disk_ops = {
+ .check = ide_check_atapi_device,
+ .get_capacity = ide_floppy_get_capacity,
+ .setup = ide_floppy_setup,
+ .flush = ide_floppy_flush,
+ .init_media = ide_floppy_init_media,
+ .set_doorlock = ide_set_media_lock,
+ .do_request = ide_floppy_do_request,
+ .end_request = ide_floppy_end_request,
+ .ioctl = ide_floppy_ioctl,
};
-
-static int ide_floppy_probe(ide_drive_t *drive)
-{
- idefloppy_floppy_t *floppy;
- struct gendisk *g;
-
- if (!strstr("ide-floppy", drive->driver_req))
- goto failed;
-
- if (drive->media != ide_floppy)
- goto failed;
-
- if (!ide_check_atapi_device(drive, DRV_NAME)) {
- printk(KERN_ERR PFX "%s: not supported by this version of "
- DRV_NAME "\n", drive->name);
- goto failed;
- }
- floppy = kzalloc(sizeof(idefloppy_floppy_t), GFP_KERNEL);
- if (!floppy) {
- printk(KERN_ERR PFX "%s: Can't allocate a floppy structure\n",
- drive->name);
- goto failed;
- }
-
- g = alloc_disk(1 << PARTN_BITS);
- if (!g)
- goto out_free_floppy;
-
- ide_init_disk(g, drive);
-
- kref_init(&floppy->kref);
-
- floppy->drive = drive;
- floppy->driver = &idefloppy_driver;
- floppy->disk = g;
-
- g->private_data = &floppy->driver;
-
- drive->driver_data = floppy;
-
- drive->debug_mask = debug_mask;
-
- idefloppy_setup(drive, floppy);
- drive->dev_flags |= IDE_DFLAG_ATTACH;
-
- g->minors = 1 << PARTN_BITS;
- g->driverfs_dev = &drive->gendev;
- if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
- g->flags = GENHD_FL_REMOVABLE;
- g->fops = &idefloppy_ops;
- add_disk(g);
- return 0;
-
-out_free_floppy:
- kfree(floppy);
-failed:
- return -ENODEV;
-}
-
-static void __exit idefloppy_exit(void)
-{
- driver_unregister(&idefloppy_driver.gen_driver);
-}
-
-static int __init idefloppy_init(void)
-{
- printk(KERN_INFO DRV_NAME " driver " IDEFLOPPY_VERSION "\n");
- return driver_register(&idefloppy_driver.gen_driver);
-}
-
-MODULE_ALIAS("ide:*m-floppy*");
-MODULE_ALIAS("ide-floppy");
-module_init(idefloppy_init);
-module_exit(idefloppy_exit);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
-
diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h
index 17cf865e583..6dd2beb4843 100644
--- a/drivers/ide/ide-floppy.h
+++ b/drivers/ide/ide-floppy.h
@@ -1,37 +1,9 @@
#ifndef __IDE_FLOPPY_H
#define __IDE_FLOPPY_H
-/*
- * Most of our global data which we need to save even as we leave the driver
- * due to an interrupt or a timer event is stored in a variable of type
- * idefloppy_floppy_t, defined below.
- */
-typedef struct ide_floppy_obj {
- ide_drive_t *drive;
- ide_driver_t *driver;
- struct gendisk *disk;
- struct kref kref;
- unsigned int openers; /* protected by BKL for now */
-
- /* Last failed packet command */
- struct ide_atapi_pc *failed_pc;
- /* used for blk_{fs,pc}_request() requests */
- struct ide_atapi_pc queued_pc;
-
- /* Last error information */
- u8 sense_key, asc, ascq;
-
- int progress_indication;
-
- /* Device information */
- /* Current format */
- int blocks, block_size, bs_factor;
- /* Last format capacity descriptor */
- u8 cap_desc[8];
- /* Copy of the flexible disk page */
- u8 flexible_disk_page[32];
-} idefloppy_floppy_t;
+#include "ide-gd.h"
+#ifdef CONFIG_IDE_GD_ATAPI
/*
* Pages of the SELECT SENSE / MODE SENSE packet commands.
* See SFF-8070i spec.
@@ -46,17 +18,22 @@ typedef struct ide_floppy_obj {
#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603
/* ide-floppy.c */
+extern const struct ide_disk_ops ide_atapi_disk_ops;
void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8);
void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
-sector_t ide_floppy_capacity(ide_drive_t *);
/* ide-floppy_ioctl.c */
-int ide_floppy_ioctl(struct inode *, struct file *, unsigned, unsigned long);
+int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t,
+ unsigned int, unsigned long);
#ifdef CONFIG_IDE_PROC_FS
/* ide-floppy_proc.c */
extern ide_proc_entry_t ide_floppy_proc[];
extern const struct ide_proc_devset ide_floppy_settings[];
#endif
+#else
+#define ide_floppy_proc NULL
+#define ide_floppy_settings NULL
+#endif
#endif /*__IDE_FLOPPY_H */
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c
index a3a7a0809e2..2bc51ff73fe 100644
--- a/drivers/ide/ide-floppy_ioctl.c
+++ b/drivers/ide/ide-floppy_ioctl.c
@@ -33,7 +33,7 @@
static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
{
- struct ide_floppy_obj *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
struct ide_atapi_pc pc;
u8 header_len, desc_cnt;
int i, blocks, length, u_array_size, u_index;
@@ -113,7 +113,7 @@ static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
static int ide_floppy_get_sfrp_bit(ide_drive_t *drive)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
struct ide_atapi_pc pc;
drive->atapi_flags &= ~IDE_AFLAG_SRFP;
@@ -132,17 +132,17 @@ static int ide_floppy_get_sfrp_bit(ide_drive_t *drive)
static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
struct ide_atapi_pc pc;
int blocks, length, flags, err = 0;
if (floppy->openers > 1) {
/* Don't format if someone is using the disk */
- drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
+ drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
return -EBUSY;
}
- drive->atapi_flags |= IDE_AFLAG_FORMAT_IN_PROGRESS;
+ drive->dev_flags |= IDE_DFLAG_FORMAT_IN_PROGRESS;
/*
* Send ATAPI_FORMAT_UNIT to the drive.
@@ -174,7 +174,7 @@ static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg)
out:
if (err)
- drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
+ drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
return err;
}
@@ -190,7 +190,7 @@ out:
static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
struct ide_atapi_pc pc;
int progress_indication = 0x10000;
@@ -226,7 +226,7 @@ static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg)
static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
unsigned long arg, unsigned int cmd)
{
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_disk_obj *floppy = drive->driver_data;
struct gendisk *disk = floppy->disk;
int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0;
@@ -241,7 +241,7 @@ static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
return 0;
}
-static int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file,
+static int ide_floppy_format_ioctl(ide_drive_t *drive, fmode_t mode,
unsigned int cmd, void __user *argp)
{
switch (cmd) {
@@ -250,7 +250,7 @@ static int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file,
case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
return ide_floppy_get_format_capacities(drive, argp);
case IDEFLOPPY_IOCTL_FORMAT_START:
- if (!(file->f_mode & 2))
+ if (!(mode & FMODE_WRITE))
return -EPERM;
return ide_floppy_format_unit(drive, (int __user *)argp);
case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
@@ -260,13 +260,9 @@ static int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file,
}
}
-int ide_floppy_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
+ fmode_t mode, unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
- struct ide_floppy_obj *floppy = ide_drv_g(bdev->bd_disk,
- ide_floppy_obj);
- ide_drive_t *drive = floppy->drive;
struct ide_atapi_pc pc;
void __user *argp = (void __user *)arg;
int err;
@@ -274,7 +270,7 @@ int ide_floppy_ioctl(struct inode *inode, struct file *file,
if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR)
return ide_floppy_lockdoor(drive, &pc, arg, cmd);
- err = ide_floppy_format_ioctl(drive, file, cmd, argp);
+ err = ide_floppy_format_ioctl(drive, mode, cmd, argp);
if (err != -ENOTTY)
return err;
@@ -283,11 +279,11 @@ int ide_floppy_ioctl(struct inode *inode, struct file *file,
* and CDROM_SEND_PACKET (legacy) ioctls
*/
if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
- err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
- bdev->bd_disk, cmd, argp);
+ err = scsi_cmd_ioctl(bdev->bd_disk->queue, bdev->bd_disk,
+ mode, cmd, argp);
if (err == -ENOTTY)
- err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+ err = generic_ide_ioctl(drive, bdev, cmd, arg);
return err;
}
diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c
index 76f0c6c4eca..3ec762cb60a 100644
--- a/drivers/ide/ide-floppy_proc.c
+++ b/drivers/ide/ide-floppy_proc.c
@@ -9,7 +9,7 @@ static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
ide_drive_t*drive = (ide_drive_t *)data;
int len;
- len = sprintf(page, "%llu\n", (long long)ide_floppy_capacity(drive));
+ len = sprintf(page, "%llu\n", (long long)ide_gd_capacity(drive));
PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
new file mode 100644
index 00000000000..7b666285437
--- /dev/null
+++ b/drivers/ide/ide-gd.c
@@ -0,0 +1,396 @@
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/mutex.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
+#define IDE_DISK_MINORS (1 << PARTN_BITS)
+#else
+#define IDE_DISK_MINORS 0
+#endif
+
+#include "ide-disk.h"
+#include "ide-floppy.h"
+
+#define IDE_GD_VERSION "1.18"
+
+/* module parameters */
+static unsigned long debug_mask;
+module_param(debug_mask, ulong, 0644);
+
+static DEFINE_MUTEX(ide_disk_ref_mutex);
+
+static void ide_disk_release(struct kref *);
+
+static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
+{
+ struct ide_disk_obj *idkp = NULL;
+
+ mutex_lock(&ide_disk_ref_mutex);
+ idkp = ide_drv_g(disk, ide_disk_obj);
+ if (idkp) {
+ if (ide_device_get(idkp->drive))
+ idkp = NULL;
+ else
+ kref_get(&idkp->kref);
+ }
+ mutex_unlock(&ide_disk_ref_mutex);
+ return idkp;
+}
+
+static void ide_disk_put(struct ide_disk_obj *idkp)
+{
+ ide_drive_t *drive = idkp->drive;
+
+ mutex_lock(&ide_disk_ref_mutex);
+ kref_put(&idkp->kref, ide_disk_release);
+ ide_device_put(drive);
+ mutex_unlock(&ide_disk_ref_mutex);
+}
+
+sector_t ide_gd_capacity(ide_drive_t *drive)
+{
+ return drive->capacity64;
+}
+
+static int ide_gd_probe(ide_drive_t *);
+
+static void ide_gd_remove(ide_drive_t *drive)
+{
+ struct ide_disk_obj *idkp = drive->driver_data;
+ struct gendisk *g = idkp->disk;
+
+ ide_proc_unregister_driver(drive, idkp->driver);
+
+ del_gendisk(g);
+
+ drive->disk_ops->flush(drive);
+
+ ide_disk_put(idkp);
+}
+
+static void ide_disk_release(struct kref *kref)
+{
+ struct ide_disk_obj *idkp = to_ide_drv(kref, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+ struct gendisk *g = idkp->disk;
+
+ drive->disk_ops = NULL;
+ drive->driver_data = NULL;
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(idkp);
+}
+
+/*
+ * On HPA drives the capacity needs to be
+ * reinitilized on resume otherwise the disk
+ * can not be used and a hard reset is required
+ */
+static void ide_gd_resume(ide_drive_t *drive)
+{
+ if (ata_id_hpa_enabled(drive->id))
+ (void)drive->disk_ops->get_capacity(drive);
+}
+
+static void ide_gd_shutdown(ide_drive_t *drive)
+{
+#ifdef CONFIG_ALPHA
+ /* On Alpha, halt(8) doesn't actually turn the machine off,
+ it puts you into the sort of firmware monitor. Typically,
+ it's used to boot another kernel image, so it's not much
+ different from reboot(8). Therefore, we don't need to
+ spin down the disk in this case, especially since Alpha
+ firmware doesn't handle disks in standby mode properly.
+ On the other hand, it's reasonably safe to turn the power
+ off when the shutdown process reaches the firmware prompt,
+ as the firmware initialization takes rather long time -
+ at least 10 seconds, which should be sufficient for
+ the disk to expire its write cache. */
+ if (system_state != SYSTEM_POWER_OFF) {
+#else
+ if (system_state == SYSTEM_RESTART) {
+#endif
+ drive->disk_ops->flush(drive);
+ return;
+ }
+
+ printk(KERN_INFO "Shutdown: %s\n", drive->name);
+
+ drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
+}
+
+#ifdef CONFIG_IDE_PROC_FS
+static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive)
+{
+ return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc;
+}
+
+static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive)
+{
+ return (drive->media == ide_disk) ? ide_disk_settings
+ : ide_floppy_settings;
+}
+#endif
+
+static ide_startstop_t ide_gd_do_request(ide_drive_t *drive,
+ struct request *rq, sector_t sector)
+{
+ return drive->disk_ops->do_request(drive, rq, sector);
+}
+
+static int ide_gd_end_request(ide_drive_t *drive, int uptodate, int nrsecs)
+{
+ return drive->disk_ops->end_request(drive, uptodate, nrsecs);
+}
+
+static ide_driver_t ide_gd_driver = {
+ .gen_driver = {
+ .owner = THIS_MODULE,
+ .name = "ide-gd",
+ .bus = &ide_bus_type,
+ },
+ .probe = ide_gd_probe,
+ .remove = ide_gd_remove,
+ .resume = ide_gd_resume,
+ .shutdown = ide_gd_shutdown,
+ .version = IDE_GD_VERSION,
+ .do_request = ide_gd_do_request,
+ .end_request = ide_gd_end_request,
+ .error = __ide_error,
+#ifdef CONFIG_IDE_PROC_FS
+ .proc_entries = ide_disk_proc_entries,
+ .proc_devsets = ide_disk_proc_devsets,
+#endif
+};
+
+static int ide_gd_open(struct block_device *bdev, fmode_t mode)
+{
+ struct gendisk *disk = bdev->bd_disk;
+ struct ide_disk_obj *idkp;
+ ide_drive_t *drive;
+ int ret = 0;
+
+ idkp = ide_disk_get(disk);
+ if (idkp == NULL)
+ return -ENXIO;
+
+ drive = idkp->drive;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ idkp->openers++;
+
+ if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
+ drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
+ /* Just in case */
+
+ ret = drive->disk_ops->init_media(drive, disk);
+
+ /*
+ * Allow O_NDELAY to open a drive without a disk, or with an
+ * unreadable disk, so that we can get the format capacity
+ * of the drive or begin the format - Sam
+ */
+ if (ret && (mode & FMODE_NDELAY) == 0) {
+ ret = -EIO;
+ goto out_put_idkp;
+ }
+
+ if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) {
+ ret = -EROFS;
+ goto out_put_idkp;
+ }
+
+ /*
+ * Ignore the return code from door_lock,
+ * since the open() has already succeeded,
+ * and the door_lock is irrelevant at this point.
+ */
+ drive->disk_ops->set_doorlock(drive, disk, 1);
+ drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
+ check_disk_change(bdev);
+ } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) {
+ ret = -EBUSY;
+ goto out_put_idkp;
+ }
+ return 0;
+
+out_put_idkp:
+ idkp->openers--;
+ ide_disk_put(idkp);
+ return ret;
+}
+
+static int ide_gd_release(struct gendisk *disk, fmode_t mode)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ if (idkp->openers == 1)
+ drive->disk_ops->flush(drive);
+
+ if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
+ drive->disk_ops->set_doorlock(drive, disk, 0);
+ drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
+ }
+
+ idkp->openers--;
+
+ ide_disk_put(idkp);
+
+ return 0;
+}
+
+static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+
+ geo->heads = drive->bios_head;
+ geo->sectors = drive->bios_sect;
+ geo->cylinders = (u16)drive->bios_cyl; /* truncate */
+ return 0;
+}
+
+static int ide_gd_media_changed(struct gendisk *disk)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+ int ret;
+
+ /* do not scan partitions twice if this is a removable device */
+ if (drive->dev_flags & IDE_DFLAG_ATTACH) {
+ drive->dev_flags &= ~IDE_DFLAG_ATTACH;
+ return 0;
+ }
+
+ ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED);
+ drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
+
+ return ret;
+}
+
+static int ide_gd_revalidate_disk(struct gendisk *disk)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
+ set_capacity(disk, ide_gd_capacity(idkp->drive));
+ return 0;
+}
+
+static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+
+ return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg);
+}
+
+static struct block_device_operations ide_gd_ops = {
+ .owner = THIS_MODULE,
+ .open = ide_gd_open,
+ .release = ide_gd_release,
+ .locked_ioctl = ide_gd_ioctl,
+ .getgeo = ide_gd_getgeo,
+ .media_changed = ide_gd_media_changed,
+ .revalidate_disk = ide_gd_revalidate_disk
+};
+
+static int ide_gd_probe(ide_drive_t *drive)
+{
+ const struct ide_disk_ops *disk_ops = NULL;
+ struct ide_disk_obj *idkp;
+ struct gendisk *g;
+
+ /* strstr("foo", "") is non-NULL */
+ if (!strstr("ide-gd", drive->driver_req))
+ goto failed;
+
+#ifdef CONFIG_IDE_GD_ATA
+ if (drive->media == ide_disk)
+ disk_ops = &ide_ata_disk_ops;
+#endif
+#ifdef CONFIG_IDE_GD_ATAPI
+ if (drive->media == ide_floppy)
+ disk_ops = &ide_atapi_disk_ops;
+#endif
+ if (disk_ops == NULL)
+ goto failed;
+
+ if (disk_ops->check(drive, DRV_NAME) == 0) {
+ printk(KERN_ERR PFX "%s: not supported by this driver\n",
+ drive->name);
+ goto failed;
+ }
+
+ idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
+ if (!idkp) {
+ printk(KERN_ERR PFX "%s: can't allocate a disk structure\n",
+ drive->name);
+ goto failed;
+ }
+
+ g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
+ if (!g)
+ goto out_free_idkp;
+
+ ide_init_disk(g, drive);
+
+ kref_init(&idkp->kref);
+
+ idkp->drive = drive;
+ idkp->driver = &ide_gd_driver;
+ idkp->disk = g;
+
+ g->private_data = &idkp->driver;
+
+ drive->driver_data = idkp;
+ drive->debug_mask = debug_mask;
+ drive->disk_ops = disk_ops;
+
+ disk_ops->setup(drive);
+
+ set_capacity(g, ide_gd_capacity(drive));
+
+ g->minors = IDE_DISK_MINORS;
+ g->driverfs_dev = &drive->gendev;
+ g->flags |= GENHD_FL_EXT_DEVT;
+ if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
+ g->flags = GENHD_FL_REMOVABLE;
+ g->fops = &ide_gd_ops;
+ add_disk(g);
+ return 0;
+
+out_free_idkp:
+ kfree(idkp);
+failed:
+ return -ENODEV;
+}
+
+static int __init ide_gd_init(void)
+{
+ printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n");
+ return driver_register(&ide_gd_driver.gen_driver);
+}
+
+static void __exit ide_gd_exit(void)
+{
+ driver_unregister(&ide_gd_driver.gen_driver);
+}
+
+MODULE_ALIAS("ide:*m-disk*");
+MODULE_ALIAS("ide-disk");
+MODULE_ALIAS("ide:*m-floppy*");
+MODULE_ALIAS("ide-floppy");
+module_init(ide_gd_init);
+module_exit(ide_gd_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("generic ATA/ATAPI disk driver");
diff --git a/drivers/ide/ide-gd.h b/drivers/ide/ide-gd.h
new file mode 100644
index 00000000000..7d3d101713e
--- /dev/null
+++ b/drivers/ide/ide-gd.h
@@ -0,0 +1,44 @@
+#ifndef __IDE_GD_H
+#define __IDE_GD_H
+
+#define DRV_NAME "ide-gd"
+#define PFX DRV_NAME ": "
+
+/* define to see debug info */
+#define IDE_GD_DEBUG_LOG 0
+
+#if IDE_GD_DEBUG_LOG
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
+#else
+#define ide_debug_log(lvl, fmt, args...) do {} while (0)
+#endif
+
+struct ide_disk_obj {
+ ide_drive_t *drive;
+ ide_driver_t *driver;
+ struct gendisk *disk;
+ struct kref kref;
+ unsigned int openers; /* protected by BKL for now */
+
+ /* Last failed packet command */
+ struct ide_atapi_pc *failed_pc;
+ /* used for blk_{fs,pc}_request() requests */
+ struct ide_atapi_pc queued_pc;
+
+ /* Last error information */
+ u8 sense_key, asc, ascq;
+
+ int progress_indication;
+
+ /* Device information */
+ /* Current format */
+ int blocks, block_size, bs_factor;
+ /* Last format capacity descriptor */
+ u8 cap_desc[8];
+ /* Copy of the flexible disk page */
+ u8 flexible_disk_page[32];
+};
+
+sector_t ide_gd_capacity(ide_drive_t *);
+
+#endif /* __IDE_GD_H */
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/ide-h8300.c
index e2cdd2e9cde..e2cdd2e9cde 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/ide-h8300.c
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
index a90945f4979..fcde16bb53a 100644
--- a/drivers/ide/ide-ioctls.c
+++ b/drivers/ide/ide-ioctls.c
@@ -240,8 +240,7 @@ static int generic_drive_reset(ide_drive_t *drive)
return ret;
}
-int generic_ide_ioctl(ide_drive_t *drive, struct file *file,
- struct block_device *bdev,
+int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
unsigned int cmd, unsigned long arg)
{
int err;
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index b762deb2dac..bb7a1ed8094 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -755,7 +755,7 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
udelay(1);
SELECT_DRIVE(drive);
- SELECT_MASK(drive, 0);
+ SELECT_MASK(drive, 1);
udelay(1);
tp_ops->set_irq(hwif, 0);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 19f8c7770a2..1649ea54f76 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -208,6 +208,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
drive->ready_stat = 0;
if (ata_id_cdb_intr(id))
drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
+ drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
/* we don't do head unloading on ATAPI devices */
drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
return;
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index b26926487cc..c31d0dd7a53 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -567,10 +567,10 @@ static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t
void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
{
mutex_lock(&ide_setting_mtx);
- drive->settings = driver->settings;
+ drive->settings = driver->proc_devsets(drive);
mutex_unlock(&ide_setting_mtx);
- ide_add_proc_entries(drive->proc, driver->proc, drive);
+ ide_add_proc_entries(drive->proc, driver->proc_entries(drive), drive);
}
EXPORT_SYMBOL(ide_proc_register_driver);
@@ -591,7 +591,7 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
{
unsigned long flags;
- ide_remove_proc_entries(drive->proc, driver->proc);
+ ide_remove_proc_entries(drive->proc, driver->proc_entries(drive));
mutex_lock(&ide_setting_mtx);
spin_lock_irqsave(&ide_lock, flags);
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index d879c7797cd..a2d470eb2b5 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -2108,7 +2108,7 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive)
/* device lacks locking support according to capabilities page */
if ((caps[6] & 1) == 0)
- drive->atapi_flags |= IDE_AFLAG_NO_DOORLOCK;
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
if (caps[7] & 0x02)
tape->blk_size = 512;
@@ -2298,6 +2298,16 @@ static ide_proc_entry_t idetape_proc[] = {
{ "name", S_IFREG|S_IRUGO, proc_idetape_read_name, NULL },
{ NULL, 0, NULL, NULL }
};
+
+static ide_proc_entry_t *ide_tape_proc_entries(ide_drive_t *drive)
+{
+ return idetape_proc;
+}
+
+static const struct ide_proc_devset *ide_tape_proc_devsets(ide_drive_t *drive)
+{
+ return idetape_settings;
+}
#endif
static int ide_tape_probe(ide_drive_t *);
@@ -2315,8 +2325,8 @@ static ide_driver_t idetape_driver = {
.end_request = idetape_end_request,
.error = __ide_error,
#ifdef CONFIG_IDE_PROC_FS
- .proc = idetape_proc,
- .settings = idetape_settings,
+ .proc_entries = ide_tape_proc_entries,
+ .proc_devsets = ide_tape_proc_devsets,
#endif
};
@@ -2330,35 +2340,30 @@ static const struct file_operations idetape_fops = {
.release = idetape_chrdev_release,
};
-static int idetape_open(struct inode *inode, struct file *filp)
+static int idetape_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct ide_tape_obj *tape;
+ struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk);
- tape = ide_tape_get(disk);
if (!tape)
return -ENXIO;
return 0;
}
-static int idetape_release(struct inode *inode, struct file *filp)
+static int idetape_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj);
ide_tape_put(tape);
-
return 0;
}
-static int idetape_ioctl(struct inode *inode, struct file *file,
+static int idetape_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
struct ide_tape_obj *tape = ide_drv_g(bdev->bd_disk, ide_tape_obj);
ide_drive_t *drive = tape->drive;
- int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+ int err = generic_ide_ioctl(drive, bdev, cmd, arg);
if (err == -EINVAL)
err = idetape_blkdev_ioctl(drive, cmd, arg);
return err;
@@ -2368,7 +2373,7 @@ static struct block_device_operations idetape_block_ops = {
.owner = THIS_MODULE,
.open = idetape_open,
.release = idetape_release,
- .ioctl = idetape_ioctl,
+ .locked_ioctl = idetape_ioctl,
};
static int ide_tape_probe(ide_drive_t *drive)
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/ide_arm.c
index f728f2927b5..f728f2927b5 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/ide_arm.c
diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/ide_platform.c
index 051b4ab0f35..051b4ab0f35 100644
--- a/drivers/ide/legacy/ide_platform.c
+++ b/drivers/ide/ide_platform.c
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/it8213.c
index 7c2feeb3c5e..7c2feeb3c5e 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/it8213.c
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/it821x.c
index 995e18bb313..995e18bb313 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/it821x.c
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/jmicron.c
index 9a68433cf46..9a68433cf46 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/jmicron.c
diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
deleted file mode 100644
index 6939329f89e..00000000000
--- a/drivers/ide/legacy/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-
-# link order is important here
-
-obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o
-obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o
-obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o
-obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o
-obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o
-obj-$(CONFIG_BLK_DEV_4DRIVES) += ide-4drives.o
-
-obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o
-obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o
-obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o
-obj-$(CONFIG_BLK_DEV_Q40IDE) += q40ide.o
-obj-$(CONFIG_BLK_DEV_BUDDHA) += buddha.o
-
-ifeq ($(CONFIG_BLK_DEV_IDECS), m)
- obj-m += ide-cs.o
-endif
-
-ifeq ($(CONFIG_BLK_DEV_PLATFORM), m)
- obj-m += ide_platform.o
-endif
-
-EXTRA_CFLAGS := -Idrivers/ide
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/macide.c
index 43f97cc1d30..43f97cc1d30 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/macide.c
diff --git a/drivers/ide/mips/Makefile b/drivers/ide/mips/Makefile
deleted file mode 100644
index 5873fa0b876..00000000000
--- a/drivers/ide/mips/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_BLK_DEV_IDE_AU1XXX) += au1xxx-ide.o
-
-EXTRA_CFLAGS := -Idrivers/ide
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/ns87415.c
index 13789060f40..13789060f40 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/ns87415.c
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/opti621.c
index 6048eda3cd6..6048eda3cd6 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/opti621.c
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/palm_bk3710.c
index 122ed3c072f..122ed3c072f 100644
--- a/drivers/ide/arm/palm_bk3710.c
+++ b/drivers/ide/palm_bk3710.c
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
deleted file mode 100644
index 02e6ee7d751..00000000000
--- a/drivers/ide/pci/Makefile
+++ /dev/null
@@ -1,44 +0,0 @@
-
-obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o
-obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o
-obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o
-obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o
-obj-$(CONFIG_BLK_DEV_CELLEB) += scc_pata.o
-obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o
-obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o
-obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
-obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
-obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
-obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
-obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o
-obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
-obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
-obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o
-obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
-obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
-obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
-obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o
-obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o
-obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o
-obj-$(CONFIG_BLK_DEV_PIIX) += piix.o
-obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o
-obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o
-obj-$(CONFIG_BLK_DEV_SGIIOC4) += sgiioc4.o
-obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
-obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
-obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
-obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o
-obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o
-obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o
-obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
-obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
-
-# Must appear at the end of the block
-obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.o
-ide-pci-generic-y += generic.o
-
-ifeq ($(CONFIG_BLK_DEV_CMD640), m)
- obj-m += cmd640.o
-endif
-
-EXTRA_CFLAGS := -Idrivers/ide
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
deleted file mode 100644
index fb1a3aa57f0..00000000000
--- a/drivers/ide/pci/hpt34x.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * 00:12.0 Unknown mass storage controller:
- * Triones Technologies, Inc.
- * Unknown device 0003 (rev 01)
- *
- * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
- * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
- * hde: DMA 2 (0x0000 0x0002) (0x0000 0x0010)
- * hdf: DMA 2 (0x0002 0x0012) (0x0010 0x0030)
- * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070)
- * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0)
- *
- * ide-pci.c reference
- *
- * Since there are two cards that report almost identically,
- * the only discernable difference is the values reported in pcicmd.
- * Booting-BIOS card or HPT363 :: pcicmd == 0x07
- * Non-bootable card or HPT343 :: pcicmd == 0x05
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "hpt34x"
-
-#define HPT343_DEBUG_DRIVE_INFO 0
-
-static void hpt34x_set_mode(ide_drive_t *drive, const u8 speed)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
- u8 hi_speed, lo_speed;
-
- hi_speed = speed >> 4;
- lo_speed = speed & 0x0f;
-
- if (hi_speed & 7) {
- hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
- } else {
- lo_speed <<= 5;
- lo_speed >>= 5;
- }
-
- pci_read_config_dword(dev, 0x44, &reg1);
- pci_read_config_dword(dev, 0x48, &reg2);
- tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
- tmp2 = ((hi_speed << drive->dn) | (reg2 & ~(0x11 << drive->dn)));
- pci_write_config_dword(dev, 0x44, tmp1);
- pci_write_config_dword(dev, 0x48, tmp2);
-
-#if HPT343_DEBUG_DRIVE_INFO
- printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
- " (0x%02x 0x%02x)\n",
- drive->name, ide_xfer_verbose(speed),
- drive->dn, reg1, tmp1, reg2, tmp2,
- hi_speed, lo_speed);
-#endif /* HPT343_DEBUG_DRIVE_INFO */
-}
-
-static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- hpt34x_set_mode(drive, XFER_PIO_0 + pio);
-}
-
-/*
- * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
- */
-#define HPT34X_PCI_INIT_REG 0x80
-
-static unsigned int init_chipset_hpt34x(struct pci_dev *dev)
-{
- int i = 0;
- unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
- unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c };
- unsigned long hpt_addr_len[4] = { 7, 3, 7, 3 };
- u16 cmd;
- unsigned long flags;
-
- local_irq_save(flags);
-
- pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
- if (cmd & PCI_COMMAND_MEMORY)
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
- else
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-
- /*
- * Since 20-23 can be assigned and are R/W, we correct them.
- */
- pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
- for(i=0; i<4; i++) {
- dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]);
- dev->resource[i].end = dev->resource[i].start + hpt_addr_len[i];
- dev->resource[i].flags = IORESOURCE_IO;
- pci_write_config_dword(dev,
- (PCI_BASE_ADDRESS_0 + (i * 4)),
- dev->resource[i].start);
- }
- pci_write_config_word(dev, PCI_COMMAND, cmd);
-
- local_irq_restore(flags);
-
- return dev->irq;
-}
-
-static const struct ide_port_ops hpt34x_port_ops = {
- .set_pio_mode = hpt34x_set_pio_mode,
- .set_dma_mode = hpt34x_set_mode,
-};
-
-#define IDE_HFLAGS_HPT34X \
- (IDE_HFLAG_NO_ATAPI_DMA | \
- IDE_HFLAG_NO_DSC | \
- IDE_HFLAG_NO_AUTODMA)
-
-static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
- { /* 0: HPT343 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_hpt34x,
- .port_ops = &hpt34x_port_ops,
- .host_flags = IDE_HFLAGS_HPT34X | IDE_HFLAG_NON_BOOTABLE,
- .pio_mask = ATA_PIO5,
- },
- { /* 1: HPT345 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_hpt34x,
- .port_ops = &hpt34x_port_ops,
- .host_flags = IDE_HFLAGS_HPT34X | IDE_HFLAG_OFF_BOARD,
- .pio_mask = ATA_PIO5,
-#ifdef CONFIG_HPT34X_AUTODMA
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA2,
-#endif
- }
-};
-
-static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- const struct ide_port_info *d;
- u16 pcicmd = 0;
-
- pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
-
- d = &hpt34x_chipsets[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0];
-
- return ide_pci_init_one(dev, d, NULL);
-}
-
-static const struct pci_device_id hpt34x_pci_tbl[] = {
- { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl);
-
-static struct pci_driver hpt34x_pci_driver = {
- .name = "HPT34x_IDE",
- .id_table = hpt34x_pci_tbl,
- .probe = hpt34x_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init hpt34x_ide_init(void)
-{
- return ide_pci_register_driver(&hpt34x_pci_driver);
-}
-
-static void __exit hpt34x_ide_exit(void)
-{
- pci_unregister_driver(&hpt34x_pci_driver);
-}
-
-module_init(hpt34x_ide_init);
-module_exit(hpt34x_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for Highpoint 34x IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c
index 211ae46e3e0..211ae46e3e0 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pdc202xx_new.c
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c
index 799557c25ee..799557c25ee 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pdc202xx_old.c
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/piix.c
index d63f9fdca76..d63f9fdca76 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/piix.c
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/pmac.c
index 2e19d629853..2e19d629853 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/pmac.c
diff --git a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile
deleted file mode 100644
index 74e52adcdf4..00000000000
--- a/drivers/ide/ppc/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-
-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/q40ide.c
index 4af4a8ce4cd..4af4a8ce4cd 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/q40ide.c
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/qd65xx.c
index bc27c7aba93..bc27c7aba93 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/qd65xx.c
diff --git a/drivers/ide/legacy/qd65xx.h b/drivers/ide/qd65xx.h
index c83dea85e62..c83dea85e62 100644
--- a/drivers/ide/legacy/qd65xx.h
+++ b/drivers/ide/qd65xx.h
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/rapide.c
index 78d27d9ae43..78d27d9ae43 100644
--- a/drivers/ide/arm/rapide.c
+++ b/drivers/ide/rapide.c
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/rz1000.c
index 7daf0135cba..7daf0135cba 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/rz1000.c
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/sc1200.c
index f1a8758e3a9..f1a8758e3a9 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/sc1200.c
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/scc_pata.c
index 9ce1d805992..49f163aa51e 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/scc_pata.c
@@ -617,7 +617,6 @@ static int __devinit init_setup_scc(struct pci_dev *dev,
unsigned long intmask_port;
unsigned long mode_port;
unsigned long ecmode_port;
- unsigned long dma_status_port;
u32 reg = 0;
struct scc_ports *ports;
int rc;
@@ -637,7 +636,6 @@ static int __devinit init_setup_scc(struct pci_dev *dev,
intmask_port = dma_base + 0x010;
mode_port = ctl_base + 0x024;
ecmode_port = ctl_base + 0xf00;
- dma_status_port = dma_base + 0x004;
/* controller initialization */
reg = 0;
@@ -843,8 +841,6 @@ static u8 scc_cable_detect(ide_hwif_t *hwif)
static void __devinit init_hwif_scc(ide_hwif_t *hwif)
{
- struct scc_ports *ports = ide_get_hwifdata(hwif);
-
/* PTERADD */
out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma);
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/serverworks.c
index 437bc919daf..437bc919daf 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/serverworks.c
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/sgiioc4.c
index dd634541ce3..8af9b23499f 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/sgiioc4.c
@@ -101,18 +101,8 @@ sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
for (i = 0; i <= 7; i++)
hw->io_ports_array[i] = reg + i * 4;
- if (ctrl_port)
- hw->io_ports.ctl_addr = ctrl_port;
-
- if (irq_port)
- hw->io_ports.irq_addr = irq_port;
-}
-
-static void
-sgiioc4_maskproc(ide_drive_t * drive, int mask)
-{
- writeb(ATA_DEVCTL_OBS | (mask ? 2 : 0),
- (void __iomem *)drive->hwif->io_ports.ctl_addr);
+ hw->io_ports.ctl_addr = ctrl_port;
+ hw->io_ports.irq_addr = irq_port;
}
static int
@@ -310,16 +300,14 @@ static u8 sgiioc4_read_status(ide_hwif_t *hwif)
unsigned long port = hwif->io_ports.status_addr;
u8 reg = (u8) readb((void __iomem *) port);
- if ((port & 0xFFF) == 0x11C) { /* Status register of IOC4 */
- if (!(reg & ATA_BUSY)) { /* Not busy... check for interrupt */
- unsigned long other_ir = port - 0x110;
- unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
+ if (!(reg & ATA_BUSY)) { /* Not busy... check for interrupt */
+ unsigned long other_ir = port - 0x110;
+ unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
- /* Clear the Interrupt, Error bits on the IOC4 */
- if (intr_reg & 0x03) {
- writel(0x03, (void __iomem *) other_ir);
- intr_reg = (u32) readl((void __iomem *) other_ir);
- }
+ /* Clear the Interrupt, Error bits on the IOC4 */
+ if (intr_reg & 0x03) {
+ writel(0x03, (void __iomem *) other_ir);
+ intr_reg = (u32) readl((void __iomem *) other_ir);
}
}
@@ -332,13 +320,9 @@ ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
- void __iomem *virt_dma_base;
int num_ports = sizeof (ioc4_dma_regs_t);
void *pad;
- if (dma_base == 0)
- return -1;
-
printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name);
if (request_mem_region(dma_base, num_ports, hwif->name) == NULL) {
@@ -348,14 +332,8 @@ ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
return -1;
}
- virt_dma_base = ioremap(dma_base, num_ports);
- if (virt_dma_base == NULL) {
- printk(KERN_ERR "%s(%s) -- ERROR: unable to map addresses "
- "0x%lx to 0x%lx\n", __func__, hwif->name,
- dma_base, dma_base + num_ports - 1);
- goto dma_remap_failure;
- }
- hwif->dma_base = (unsigned long) virt_dma_base;
+ hwif->dma_base = (unsigned long)hwif->io_ports.irq_addr +
+ IOC4_DMA_OFFSET;
hwif->sg_max_nents = IOC4_PRD_ENTRIES;
@@ -379,9 +357,6 @@ ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
printk(KERN_INFO "%s: changing from DMA to PIO mode", hwif->name);
dma_pci_alloc_failure:
- iounmap(virt_dma_base);
-
-dma_remap_failure:
release_mem_region(dma_base, num_ports);
return -1;
@@ -563,8 +538,6 @@ static const struct ide_port_ops sgiioc4_port_ops = {
.set_dma_mode = sgiioc4_set_dma_mode,
/* reset DMA engine, clear IRQs */
.resetproc = sgiioc4_resetproc,
- /* mask on/off NIEN register */
- .maskproc = sgiioc4_maskproc,
};
static const struct ide_dma_ops sgiioc4_dma_ops = {
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/siimage.c
index eb4faf92c57..eb4faf92c57 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/siimage.c
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/sis5513.c
index ad32e18c5ba..ad32e18c5ba 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/sis5513.c
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/sl82c105.c
index 84dc33602ff..84dc33602ff 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/sl82c105.c
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/slc90e66.c
index 0f759e4ed77..0f759e4ed77 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/slc90e66.c
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/tc86c001.c
index 93e2cce4b29..93e2cce4b29 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/tc86c001.c
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/triflex.c
index b6ff40336aa..b6ff40336aa 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/triflex.c
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/trm290.c
index 75ea6152656..75ea6152656 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/trm290.c
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/umc8672.c
index 1da076e0c91..1da076e0c91 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/umc8672.c
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/via82cxxx.c
index 2a812d3207e..2a812d3207e 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
diff --git a/drivers/idle/Kconfig b/drivers/idle/Kconfig
new file mode 100644
index 00000000000..f5b26dd579e
--- /dev/null
+++ b/drivers/idle/Kconfig
@@ -0,0 +1,16 @@
+
+menu "Memory power savings"
+
+config I7300_IDLE_IOAT_CHANNEL
+ bool
+
+config I7300_IDLE
+ tristate "Intel chipset idle power saving driver"
+ select I7300_IDLE_IOAT_CHANNEL
+ depends on X86_64
+ help
+ Enable idle power savings with certain Intel server chipsets.
+ The chipset must have I/O AT support, such as the Intel 7300.
+ The power savings depends on the type and quantity of DRAM devices.
+
+endmenu
diff --git a/drivers/idle/Makefile b/drivers/idle/Makefile
new file mode 100644
index 00000000000..5f68fc377e2
--- /dev/null
+++ b/drivers/idle/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_I7300_IDLE) += i7300_idle.o
+
diff --git a/drivers/idle/i7300_idle.c b/drivers/idle/i7300_idle.c
new file mode 100644
index 00000000000..59d1bbc3cd3
--- /dev/null
+++ b/drivers/idle/i7300_idle.c
@@ -0,0 +1,674 @@
+/*
+ * (C) Copyright 2008 Intel Corporation
+ * Authors:
+ * Andy Henroid <andrew.d.henroid@intel.com>
+ * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ */
+
+/*
+ * Save DIMM power on Intel 7300-based platforms when all CPUs/cores
+ * are idle, using the DIMM thermal throttling capability.
+ *
+ * This driver depends on the Intel integrated DMA controller (I/O AT).
+ * If the driver for I/O AT (drivers/dma/ioatdma*) is also enabled,
+ * this driver should work cooperatively.
+ */
+
+/* #define DEBUG */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/cpumask.h>
+#include <linux/ktime.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/stop_machine.h>
+
+#include <asm/idle.h>
+
+#include "../dma/ioatdma_hw.h"
+#include "../dma/ioatdma_registers.h"
+
+#define I7300_IDLE_DRIVER_VERSION "1.55"
+#define I7300_PRINT "i7300_idle:"
+
+static int debug;
+module_param_named(debug, debug, uint, 0644);
+MODULE_PARM_DESC(debug, "Enable debug printks in this driver");
+
+#define dprintk(fmt, arg...) \
+ do { if (debug) printk(KERN_INFO I7300_PRINT fmt, ##arg); } while (0)
+
+/*
+ * Value to set THRTLOW to when initiating throttling
+ * 0 = No throttling
+ * 1 = Throttle when > 4 activations per eval window (Maximum throttling)
+ * 2 = Throttle when > 8 activations
+ * 168 = Throttle when > 168 activations (Minimum throttling)
+ */
+#define MAX_THRTLWLIMIT 168
+static uint i7300_idle_thrtlowlm = 1;
+module_param_named(thrtlwlimit, i7300_idle_thrtlowlm, uint, 0644);
+MODULE_PARM_DESC(thrtlwlimit,
+ "Value for THRTLOWLM activation field "
+ "(0 = disable throttle, 1 = Max throttle, 168 = Min throttle)");
+
+/*
+ * simple invocation and duration statistics
+ */
+static unsigned long total_starts;
+static unsigned long total_us;
+
+#ifdef DEBUG
+static unsigned long past_skip;
+#endif
+
+static struct pci_dev *fbd_dev;
+
+static spinlock_t i7300_idle_lock;
+static int i7300_idle_active;
+
+static u8 i7300_idle_thrtctl_saved;
+static u8 i7300_idle_thrtlow_saved;
+static u32 i7300_idle_mc_saved;
+
+static cpumask_t idle_cpumask;
+static ktime_t start_ktime;
+static unsigned long avg_idle_us;
+
+static struct dentry *debugfs_dir;
+
+/* Begin: I/O AT Helper routines */
+
+#define IOAT_CHANBASE(ioat_ctl, chan) (ioat_ctl + 0x80 + 0x80 * chan)
+/* Snoop control (disable snoops when coherency is not important) */
+#define IOAT_DESC_SADDR_SNP_CTL (1UL << 1)
+#define IOAT_DESC_DADDR_SNP_CTL (1UL << 2)
+
+static struct pci_dev *ioat_dev;
+static struct ioat_dma_descriptor *ioat_desc; /* I/O AT desc & data (1 page) */
+static unsigned long ioat_desc_phys;
+static u8 *ioat_iomap; /* I/O AT memory-mapped control regs (aka CB_BAR) */
+static u8 *ioat_chanbase;
+
+/* Start I/O AT memory copy */
+static int i7300_idle_ioat_start(void)
+{
+ u32 err;
+ /* Clear error (due to circular descriptor pointer) */
+ err = readl(ioat_chanbase + IOAT_CHANERR_OFFSET);
+ if (err)
+ writel(err, ioat_chanbase + IOAT_CHANERR_OFFSET);
+
+ writeb(IOAT_CHANCMD_START, ioat_chanbase + IOAT1_CHANCMD_OFFSET);
+ return 0;
+}
+
+/* Stop I/O AT memory copy */
+static void i7300_idle_ioat_stop(void)
+{
+ int i;
+ u8 sts;
+
+ for (i = 0; i < 5; i++) {
+ writeb(IOAT_CHANCMD_RESET,
+ ioat_chanbase + IOAT1_CHANCMD_OFFSET);
+
+ udelay(10);
+
+ sts = readq(ioat_chanbase + IOAT1_CHANSTS_OFFSET) &
+ IOAT_CHANSTS_DMA_TRANSFER_STATUS;
+
+ if (sts != IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE)
+ break;
+
+ }
+
+ if (i == 5)
+ dprintk("failed to suspend+reset I/O AT after 5 retries\n");
+
+}
+
+/* Test I/O AT by copying 1024 byte from 2k to 1k */
+static int __init i7300_idle_ioat_selftest(u8 *ctl,
+ struct ioat_dma_descriptor *desc, unsigned long desc_phys)
+{
+ u64 chan_sts;
+
+ memset(desc, 0, 2048);
+ memset((u8 *) desc + 2048, 0xab, 1024);
+
+ desc[0].size = 1024;
+ desc[0].ctl = 0;
+ desc[0].src_addr = desc_phys + 2048;
+ desc[0].dst_addr = desc_phys + 1024;
+ desc[0].next = 0;
+
+ writeb(IOAT_CHANCMD_RESET, ioat_chanbase + IOAT1_CHANCMD_OFFSET);
+ writeb(IOAT_CHANCMD_START, ioat_chanbase + IOAT1_CHANCMD_OFFSET);
+
+ udelay(1000);
+
+ chan_sts = readq(ioat_chanbase + IOAT1_CHANSTS_OFFSET) &
+ IOAT_CHANSTS_DMA_TRANSFER_STATUS;
+
+ if (chan_sts != IOAT_CHANSTS_DMA_TRANSFER_STATUS_DONE) {
+ /* Not complete, reset the channel */
+ writeb(IOAT_CHANCMD_RESET,
+ ioat_chanbase + IOAT1_CHANCMD_OFFSET);
+ return -1;
+ }
+
+ if (*(u32 *) ((u8 *) desc + 3068) != 0xabababab ||
+ *(u32 *) ((u8 *) desc + 2044) != 0xabababab) {
+ dprintk("Data values src 0x%x, dest 0x%x, memset 0x%x\n",
+ *(u32 *) ((u8 *) desc + 2048),
+ *(u32 *) ((u8 *) desc + 1024),
+ *(u32 *) ((u8 *) desc + 3072));
+ return -1;
+ }
+ return 0;
+}
+
+static struct device dummy_dma_dev = {
+ .bus_id = "fallback device",
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ .dma_mask = &dummy_dma_dev.coherent_dma_mask,
+};
+
+/* Setup and initialize I/O AT */
+/* This driver needs I/O AT as the throttling takes effect only when there is
+ * some memory activity. We use I/O AT to set up a dummy copy, while all CPUs
+ * go idle and memory is throttled.
+ */
+static int __init i7300_idle_ioat_init(void)
+{
+ u8 ver, chan_count, ioat_chan;
+ u16 chan_ctl;
+
+ ioat_iomap = (u8 *) ioremap_nocache(pci_resource_start(ioat_dev, 0),
+ pci_resource_len(ioat_dev, 0));
+
+ if (!ioat_iomap) {
+ printk(KERN_ERR I7300_PRINT "failed to map I/O AT registers\n");
+ goto err_ret;
+ }
+
+ ver = readb(ioat_iomap + IOAT_VER_OFFSET);
+ if (ver != IOAT_VER_1_2) {
+ printk(KERN_ERR I7300_PRINT "unknown I/O AT version (%u.%u)\n",
+ ver >> 4, ver & 0xf);
+ goto err_unmap;
+ }
+
+ chan_count = readb(ioat_iomap + IOAT_CHANCNT_OFFSET);
+ if (!chan_count) {
+ printk(KERN_ERR I7300_PRINT "unexpected # of I/O AT channels "
+ "(%u)\n",
+ chan_count);
+ goto err_unmap;
+ }
+
+ ioat_chan = chan_count - 1;
+ ioat_chanbase = IOAT_CHANBASE(ioat_iomap, ioat_chan);
+
+ chan_ctl = readw(ioat_chanbase + IOAT_CHANCTRL_OFFSET);
+ if (chan_ctl & IOAT_CHANCTRL_CHANNEL_IN_USE) {
+ printk(KERN_ERR I7300_PRINT "channel %d in use\n", ioat_chan);
+ goto err_unmap;
+ }
+
+ writew(IOAT_CHANCTRL_CHANNEL_IN_USE,
+ ioat_chanbase + IOAT_CHANCTRL_OFFSET);
+
+ ioat_desc = (struct ioat_dma_descriptor *)dma_alloc_coherent(
+ &dummy_dma_dev, 4096,
+ (dma_addr_t *)&ioat_desc_phys, GFP_KERNEL);
+ if (!ioat_desc) {
+ printk(KERN_ERR I7300_PRINT "failed to allocate I/O AT desc\n");
+ goto err_mark_unused;
+ }
+
+ writel(ioat_desc_phys & 0xffffffffUL,
+ ioat_chanbase + IOAT1_CHAINADDR_OFFSET_LOW);
+ writel(ioat_desc_phys >> 32,
+ ioat_chanbase + IOAT1_CHAINADDR_OFFSET_HIGH);
+
+ if (i7300_idle_ioat_selftest(ioat_iomap, ioat_desc, ioat_desc_phys)) {
+ printk(KERN_ERR I7300_PRINT "I/O AT self-test failed\n");
+ goto err_free;
+ }
+
+ /* Setup circular I/O AT descriptor chain */
+ ioat_desc[0].ctl = IOAT_DESC_SADDR_SNP_CTL | IOAT_DESC_DADDR_SNP_CTL;
+ ioat_desc[0].src_addr = ioat_desc_phys + 2048;
+ ioat_desc[0].dst_addr = ioat_desc_phys + 3072;
+ ioat_desc[0].size = 128;
+ ioat_desc[0].next = ioat_desc_phys + sizeof(struct ioat_dma_descriptor);
+
+ ioat_desc[1].ctl = ioat_desc[0].ctl;
+ ioat_desc[1].src_addr = ioat_desc[0].src_addr;
+ ioat_desc[1].dst_addr = ioat_desc[0].dst_addr;
+ ioat_desc[1].size = ioat_desc[0].size;
+ ioat_desc[1].next = ioat_desc_phys;
+
+ return 0;
+
+err_free:
+ dma_free_coherent(&dummy_dma_dev, 4096, (void *)ioat_desc, 0);
+err_mark_unused:
+ writew(0, ioat_chanbase + IOAT_CHANCTRL_OFFSET);
+err_unmap:
+ iounmap(ioat_iomap);
+err_ret:
+ return -ENODEV;
+}
+
+/* Cleanup I/O AT */
+static void __exit i7300_idle_ioat_exit(void)
+{
+ int i;
+ u64 chan_sts;
+
+ i7300_idle_ioat_stop();
+
+ /* Wait for a while for the channel to halt before releasing */
+ for (i = 0; i < 10; i++) {
+ writeb(IOAT_CHANCMD_RESET,
+ ioat_chanbase + IOAT1_CHANCMD_OFFSET);
+
+ chan_sts = readq(ioat_chanbase + IOAT1_CHANSTS_OFFSET) &
+ IOAT_CHANSTS_DMA_TRANSFER_STATUS;
+
+ if (chan_sts != IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE) {
+ writew(0, ioat_chanbase + IOAT_CHANCTRL_OFFSET);
+ break;
+ }
+ udelay(1000);
+ }
+
+ chan_sts = readq(ioat_chanbase + IOAT1_CHANSTS_OFFSET) &
+ IOAT_CHANSTS_DMA_TRANSFER_STATUS;
+
+ /*
+ * We tried to reset multiple times. If IO A/T channel is still active
+ * flag an error and return without cleanup. Memory leak is better
+ * than random corruption in that extreme error situation.
+ */
+ if (chan_sts == IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE) {
+ printk(KERN_ERR I7300_PRINT "Unable to stop IO A/T channels."
+ " Not freeing resources\n");
+ return;
+ }
+
+ dma_free_coherent(&dummy_dma_dev, 4096, (void *)ioat_desc, 0);
+ iounmap(ioat_iomap);
+}
+
+/* End: I/O AT Helper routines */
+
+#define DIMM_THRTLOW 0x64
+#define DIMM_THRTCTL 0x67
+#define DIMM_THRTCTL_THRMHUNT (1UL << 0)
+#define DIMM_MC 0x40
+#define DIMM_GTW_MODE (1UL << 17)
+#define DIMM_GBLACT 0x60
+
+/*
+ * Keep track of an exponential-decaying average of recent idle durations.
+ * The latest duration gets DURATION_WEIGHT_PCT percentage weight
+ * in this average, with the old average getting the remaining weight.
+ *
+ * High weights emphasize recent history, low weights include long history.
+ */
+#define DURATION_WEIGHT_PCT 55
+
+/*
+ * When the decaying average of recent durations or the predicted duration
+ * of the next timer interrupt is shorter than duration_threshold, the
+ * driver will decline to throttle.
+ */
+#define DURATION_THRESHOLD_US 100
+
+
+/* Store DIMM thermal throttle configuration */
+static int i7300_idle_thrt_save(void)
+{
+ u32 new_mc_val;
+ u8 gblactlm;
+
+ pci_read_config_byte(fbd_dev, DIMM_THRTCTL, &i7300_idle_thrtctl_saved);
+ pci_read_config_byte(fbd_dev, DIMM_THRTLOW, &i7300_idle_thrtlow_saved);
+ pci_read_config_dword(fbd_dev, DIMM_MC, &i7300_idle_mc_saved);
+ /*
+ * Make sure we have Global Throttling Window Mode set to have a
+ * "short" window. This (mostly) works around an issue where
+ * throttling persists until the end of the global throttling window
+ * size. On the tested system, this was resulting in a maximum of
+ * 64 ms to exit throttling (average 32 ms). The actual numbers
+ * depends on system frequencies. Setting the short window reduces
+ * this by a factor of 4096.
+ *
+ * We will only do this only if the system is set for
+ * unlimited-activations while in open-loop throttling (i.e., when
+ * Global Activation Throttle Limit is zero).
+ */
+ pci_read_config_byte(fbd_dev, DIMM_GBLACT, &gblactlm);
+ dprintk("thrtctl_saved = 0x%02x, thrtlow_saved = 0x%02x\n",
+ i7300_idle_thrtctl_saved,
+ i7300_idle_thrtlow_saved);
+ dprintk("mc_saved = 0x%08x, gblactlm = 0x%02x\n",
+ i7300_idle_mc_saved,
+ gblactlm);
+ if (gblactlm == 0) {
+ new_mc_val = i7300_idle_mc_saved | DIMM_GTW_MODE;
+ pci_write_config_dword(fbd_dev, DIMM_MC, new_mc_val);
+ return 0;
+ } else {
+ dprintk("could not set GTW_MODE = 1 (OLTT enabled)\n");
+ return -ENODEV;
+ }
+}
+
+/* Restore DIMM thermal throttle configuration */
+static void i7300_idle_thrt_restore(void)
+{
+ pci_write_config_dword(fbd_dev, DIMM_MC, i7300_idle_mc_saved);
+ pci_write_config_byte(fbd_dev, DIMM_THRTLOW, i7300_idle_thrtlow_saved);
+ pci_write_config_byte(fbd_dev, DIMM_THRTCTL, i7300_idle_thrtctl_saved);
+}
+
+/* Enable DIMM thermal throttling */
+static void i7300_idle_start(void)
+{
+ u8 new_ctl;
+ u8 limit;
+
+ new_ctl = i7300_idle_thrtctl_saved & ~DIMM_THRTCTL_THRMHUNT;
+ pci_write_config_byte(fbd_dev, DIMM_THRTCTL, new_ctl);
+
+ limit = i7300_idle_thrtlowlm;
+ if (unlikely(limit > MAX_THRTLWLIMIT))
+ limit = MAX_THRTLWLIMIT;
+
+ pci_write_config_byte(fbd_dev, DIMM_THRTLOW, limit);
+
+ new_ctl = i7300_idle_thrtctl_saved | DIMM_THRTCTL_THRMHUNT;
+ pci_write_config_byte(fbd_dev, DIMM_THRTCTL, new_ctl);
+}
+
+/* Disable DIMM thermal throttling */
+static void i7300_idle_stop(void)
+{
+ u8 new_ctl;
+ u8 got_ctl;
+
+ new_ctl = i7300_idle_thrtctl_saved & ~DIMM_THRTCTL_THRMHUNT;
+ pci_write_config_byte(fbd_dev, DIMM_THRTCTL, new_ctl);
+
+ pci_write_config_byte(fbd_dev, DIMM_THRTLOW, i7300_idle_thrtlow_saved);
+ pci_write_config_byte(fbd_dev, DIMM_THRTCTL, i7300_idle_thrtctl_saved);
+ pci_read_config_byte(fbd_dev, DIMM_THRTCTL, &got_ctl);
+ WARN_ON_ONCE(got_ctl != i7300_idle_thrtctl_saved);
+}
+
+
+/*
+ * i7300_avg_duration_check()
+ * return 0 if the decaying average of recent idle durations is
+ * more than DURATION_THRESHOLD_US
+ */
+static int i7300_avg_duration_check(void)
+{
+ if (avg_idle_us >= DURATION_THRESHOLD_US)
+ return 0;
+
+#ifdef DEBUG
+ past_skip++;
+#endif
+ return 1;
+}
+
+/* Idle notifier to look at idle CPUs */
+static int i7300_idle_notifier(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ unsigned long flags;
+ ktime_t now_ktime;
+ static ktime_t idle_begin_time;
+ static int time_init = 1;
+
+ if (!i7300_idle_thrtlowlm)
+ return 0;
+
+ if (unlikely(time_init)) {
+ time_init = 0;
+ idle_begin_time = ktime_get();
+ }
+
+ spin_lock_irqsave(&i7300_idle_lock, flags);
+ if (val == IDLE_START) {
+
+ cpu_set(smp_processor_id(), idle_cpumask);
+
+ if (cpus_weight(idle_cpumask) != num_online_cpus())
+ goto end;
+
+ now_ktime = ktime_get();
+ idle_begin_time = now_ktime;
+
+ if (i7300_avg_duration_check())
+ goto end;
+
+ i7300_idle_active = 1;
+ total_starts++;
+ start_ktime = now_ktime;
+
+ i7300_idle_start();
+ i7300_idle_ioat_start();
+
+ } else if (val == IDLE_END) {
+ cpu_clear(smp_processor_id(), idle_cpumask);
+ if (cpus_weight(idle_cpumask) == (num_online_cpus() - 1)) {
+ /* First CPU coming out of idle */
+ u64 idle_duration_us;
+
+ now_ktime = ktime_get();
+
+ idle_duration_us = ktime_to_us(ktime_sub
+ (now_ktime, idle_begin_time));
+
+ avg_idle_us =
+ ((100 - DURATION_WEIGHT_PCT) * avg_idle_us +
+ DURATION_WEIGHT_PCT * idle_duration_us) / 100;
+
+ if (i7300_idle_active) {
+ ktime_t idle_ktime;
+
+ idle_ktime = ktime_sub(now_ktime, start_ktime);
+ total_us += ktime_to_us(idle_ktime);
+
+ i7300_idle_ioat_stop();
+ i7300_idle_stop();
+ i7300_idle_active = 0;
+ }
+ }
+ }
+end:
+ spin_unlock_irqrestore(&i7300_idle_lock, flags);
+ return 0;
+}
+
+static struct notifier_block i7300_idle_nb = {
+ .notifier_call = i7300_idle_notifier,
+};
+
+/*
+ * I/O AT controls (PCI bus 0 device 8 function 0)
+ * DIMM controls (PCI bus 0 device 16 function 1)
+ */
+#define IOAT_BUS 0
+#define IOAT_DEVFN PCI_DEVFN(8, 0)
+#define MEMCTL_BUS 0
+#define MEMCTL_DEVFN PCI_DEVFN(16, 1)
+
+struct fbd_ioat {
+ unsigned int vendor;
+ unsigned int ioat_dev;
+};
+
+/*
+ * The i5000 chip-set has the same hooks as the i7300
+ * but support is disabled by default because this driver
+ * has not been validated on that platform.
+ */
+#define SUPPORT_I5000 0
+
+static const struct fbd_ioat fbd_ioat_list[] = {
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB},
+#if SUPPORT_I5000
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT},
+#endif
+ {0, 0}
+};
+
+/* table of devices that work with this driver */
+static const struct pci_device_id pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_FBD_CNB) },
+#if SUPPORT_I5000
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) },
+#endif
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+/* Check for known platforms with I/O-AT */
+static int __init i7300_idle_platform_probe(void)
+{
+ int i;
+
+ fbd_dev = pci_get_bus_and_slot(MEMCTL_BUS, MEMCTL_DEVFN);
+ if (!fbd_dev)
+ return -ENODEV;
+
+ for (i = 0; pci_tbl[i].vendor != 0; i++) {
+ if (fbd_dev->vendor == pci_tbl[i].vendor &&
+ fbd_dev->device == pci_tbl[i].device) {
+ break;
+ }
+ }
+ if (pci_tbl[i].vendor == 0)
+ return -ENODEV;
+
+ ioat_dev = pci_get_bus_and_slot(IOAT_BUS, IOAT_DEVFN);
+ if (!ioat_dev)
+ return -ENODEV;
+
+ for (i = 0; fbd_ioat_list[i].vendor != 0; i++) {
+ if (ioat_dev->vendor == fbd_ioat_list[i].vendor &&
+ ioat_dev->device == fbd_ioat_list[i].ioat_dev) {
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+int stats_open_generic(struct inode *inode, struct file *fp)
+{
+ fp->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t stats_read_ul(struct file *fp, char __user *ubuf, size_t count,
+ loff_t *off)
+{
+ unsigned long *p = fp->private_data;
+ char buf[32];
+ int len;
+
+ len = snprintf(buf, 32, "%lu\n", *p);
+ return simple_read_from_buffer(ubuf, count, off, buf, len);
+}
+
+static const struct file_operations idle_fops = {
+ .open = stats_open_generic,
+ .read = stats_read_ul,
+};
+
+struct debugfs_file_info {
+ void *ptr;
+ char name[32];
+ struct dentry *file;
+} debugfs_file_list[] = {
+ {&total_starts, "total_starts", NULL},
+ {&total_us, "total_us", NULL},
+#ifdef DEBUG
+ {&past_skip, "past_skip", NULL},
+#endif
+ {NULL, "", NULL}
+ };
+
+static int __init i7300_idle_init(void)
+{
+ spin_lock_init(&i7300_idle_lock);
+ cpus_clear(idle_cpumask);
+ total_us = 0;
+
+ if (i7300_idle_platform_probe())
+ return -ENODEV;
+
+ if (i7300_idle_thrt_save())
+ return -ENODEV;
+
+ if (i7300_idle_ioat_init())
+ return -ENODEV;
+
+ debugfs_dir = debugfs_create_dir("i7300_idle", NULL);
+ if (debugfs_dir) {
+ int i = 0;
+
+ while (debugfs_file_list[i].ptr != NULL) {
+ debugfs_file_list[i].file = debugfs_create_file(
+ debugfs_file_list[i].name,
+ S_IRUSR,
+ debugfs_dir,
+ debugfs_file_list[i].ptr,
+ &idle_fops);
+ i++;
+ }
+ }
+
+ idle_notifier_register(&i7300_idle_nb);
+
+ printk(KERN_INFO "i7300_idle: loaded v%s\n", I7300_IDLE_DRIVER_VERSION);
+ return 0;
+}
+
+static void __exit i7300_idle_exit(void)
+{
+ idle_notifier_unregister(&i7300_idle_nb);
+
+ if (debugfs_dir) {
+ int i = 0;
+
+ while (debugfs_file_list[i].file != NULL) {
+ debugfs_remove(debugfs_file_list[i].file);
+ i++;
+ }
+
+ debugfs_remove(debugfs_dir);
+ }
+ i7300_idle_thrt_restore();
+ i7300_idle_ioat_exit();
+}
+
+module_init(i7300_idle_init);
+module_exit(i7300_idle_exit);
+
+MODULE_AUTHOR("Andy Henroid <andrew.d.henroid@intel.com>");
+MODULE_DESCRIPTION("Intel Chipset DIMM Idle Power Saving Driver v"
+ I7300_IDLE_DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index a78d35aecee..f1e82a92e61 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -122,7 +122,7 @@ struct cm_counter_attribute {
#define CM_COUNTER_ATTR(_name, _index) \
struct cm_counter_attribute cm_##_name##_counter_attr = { \
- .attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
.index = _index \
}
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 49c45feccd5..5c54fc2350b 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -406,19 +406,15 @@ static int register_snoop_agent(struct ib_mad_qp_info *qp_info,
if (i == qp_info->snoop_table_size) {
/* Grow table. */
- new_snoop_table = kmalloc(sizeof mad_snoop_priv *
- qp_info->snoop_table_size + 1,
- GFP_ATOMIC);
+ new_snoop_table = krealloc(qp_info->snoop_table,
+ sizeof mad_snoop_priv *
+ (qp_info->snoop_table_size + 1),
+ GFP_ATOMIC);
if (!new_snoop_table) {
i = -ENOMEM;
goto out;
}
- if (qp_info->snoop_table) {
- memcpy(new_snoop_table, qp_info->snoop_table,
- sizeof mad_snoop_priv *
- qp_info->snoop_table_size);
- kfree(qp_info->snoop_table);
- }
+
qp_info->snoop_table = new_snoop_table;
qp_info->snoop_table_size++;
}
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 3ddacf39b7b..4346a24568f 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -904,8 +904,8 @@ static ssize_t ucma_join_multicast(struct ucma_file *file,
mutex_lock(&file->mut);
mc = ucma_alloc_multicast(ctx);
- if (IS_ERR(mc)) {
- ret = PTR_ERR(mc);
+ if (!mc) {
+ ret = -ENOMEM;
goto err1;
}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index c325c44807e..44e936e48a3 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -1942,6 +1942,7 @@ fail4:
fail3:
cxgb3_free_atid(ep->com.tdev, ep->atid);
fail2:
+ cm_id->rem_ref(cm_id);
put_ep(&ep->com);
out:
return err;
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 5d7b7855afb..4df887af66a 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -128,6 +128,8 @@ struct ehca_shca {
/* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */
u32 hca_cap_mr_pgsize;
int max_mtu;
+ int max_num_qps;
+ int max_num_cqs;
atomic_t num_cqs;
atomic_t num_qps;
};
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 33647a95eb9..2f4c28a3027 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -132,9 +132,9 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
return ERR_PTR(-EINVAL);
- if (!atomic_add_unless(&shca->num_cqs, 1, ehca_max_cq)) {
+ if (!atomic_add_unless(&shca->num_cqs, 1, shca->max_num_cqs)) {
ehca_err(device, "Unable to create CQ, max number of %i "
- "CQs reached.", ehca_max_cq);
+ "CQs reached.", shca->max_num_cqs);
ehca_err(device, "To increase the maximum number of CQs "
"use the number_of_cqs module parameter.\n");
return ERR_PTR(-ENOSPC);
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 598844d2edc..bb02a86aa52 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -44,6 +44,8 @@
#include <linux/slab.h>
#endif
+#include <linux/notifier.h>
+#include <linux/memory.h>
#include "ehca_classes.h"
#include "ehca_iverbs.h"
#include "ehca_mrmw.h"
@@ -366,22 +368,23 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];
/* Set maximum number of CQs and QPs to calculate EQ size */
- if (ehca_max_qp == -1)
- ehca_max_qp = min_t(int, rblock->max_qp, EHCA_MAX_NUM_QUEUES);
- else if (ehca_max_qp < 1 || ehca_max_qp > rblock->max_qp) {
- ehca_gen_err("Requested number of QPs is out of range (1 - %i) "
- "specified by HW", rblock->max_qp);
- ret = -EINVAL;
- goto sense_attributes1;
+ if (shca->max_num_qps == -1)
+ shca->max_num_qps = min_t(int, rblock->max_qp,
+ EHCA_MAX_NUM_QUEUES);
+ else if (shca->max_num_qps < 1 || shca->max_num_qps > rblock->max_qp) {
+ ehca_gen_warn("The requested number of QPs is out of range "
+ "(1 - %i) specified by HW. Value is set to %i",
+ rblock->max_qp, rblock->max_qp);
+ shca->max_num_qps = rblock->max_qp;
}
- if (ehca_max_cq == -1)
- ehca_max_cq = min_t(int, rblock->max_cq, EHCA_MAX_NUM_QUEUES);
- else if (ehca_max_cq < 1 || ehca_max_cq > rblock->max_cq) {
- ehca_gen_err("Requested number of CQs is out of range (1 - %i) "
- "specified by HW", rblock->max_cq);
- ret = -EINVAL;
- goto sense_attributes1;
+ if (shca->max_num_cqs == -1)
+ shca->max_num_cqs = min_t(int, rblock->max_cq,
+ EHCA_MAX_NUM_QUEUES);
+ else if (shca->max_num_cqs < 1 || shca->max_num_cqs > rblock->max_cq) {
+ ehca_gen_warn("The requested number of CQs is out of range "
+ "(1 - %i) specified by HW. Value is set to %i",
+ rblock->max_cq, rblock->max_cq);
}
/* query max MTU from first port -- it's the same for all ports */
@@ -733,9 +736,13 @@ static int __devinit ehca_probe(struct of_device *dev,
ehca_gen_err("Cannot allocate shca memory.");
return -ENOMEM;
}
+
mutex_init(&shca->modify_mutex);
atomic_set(&shca->num_cqs, 0);
atomic_set(&shca->num_qps, 0);
+ shca->max_num_qps = ehca_max_qp;
+ shca->max_num_cqs = ehca_max_cq;
+
for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
spin_lock_init(&shca->sport[i].mod_sqp_lock);
@@ -755,7 +762,7 @@ static int __devinit ehca_probe(struct of_device *dev,
goto probe1;
}
- eq_size = 2 * ehca_max_cq + 4 * ehca_max_qp;
+ eq_size = 2 * shca->max_num_cqs + 4 * shca->max_num_qps;
/* create event queues */
ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size);
if (ret) {
@@ -964,6 +971,41 @@ void ehca_poll_eqs(unsigned long data)
spin_unlock(&shca_list_lock);
}
+static int ehca_mem_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ static unsigned long ehca_dmem_warn_time;
+
+ switch (action) {
+ case MEM_CANCEL_OFFLINE:
+ case MEM_CANCEL_ONLINE:
+ case MEM_ONLINE:
+ case MEM_OFFLINE:
+ return NOTIFY_OK;
+ case MEM_GOING_ONLINE:
+ case MEM_GOING_OFFLINE:
+ /* only ok if no hca is attached to the lpar */
+ spin_lock(&shca_list_lock);
+ if (list_empty(&shca_list)) {
+ spin_unlock(&shca_list_lock);
+ return NOTIFY_OK;
+ } else {
+ spin_unlock(&shca_list_lock);
+ if (printk_timed_ratelimit(&ehca_dmem_warn_time,
+ 30 * 1000))
+ ehca_gen_err("DMEM operations are not allowed"
+ "as long as an ehca adapter is"
+ "attached to the LPAR");
+ return NOTIFY_BAD;
+ }
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block ehca_mem_nb = {
+ .notifier_call = ehca_mem_notifier,
+};
+
static int __init ehca_module_init(void)
{
int ret;
@@ -991,6 +1033,12 @@ static int __init ehca_module_init(void)
goto module_init2;
}
+ ret = register_memory_notifier(&ehca_mem_nb);
+ if (ret) {
+ ehca_gen_err("Failed registering memory add/remove notifier");
+ goto module_init3;
+ }
+
if (ehca_poll_all_eqs != 1) {
ehca_gen_err("WARNING!!!");
ehca_gen_err("It is possible to lose interrupts.");
@@ -1003,6 +1051,9 @@ static int __init ehca_module_init(void)
return 0;
+module_init3:
+ ibmebus_unregister_driver(&ehca_driver);
+
module_init2:
ehca_destroy_slab_caches();
@@ -1018,6 +1069,8 @@ static void __exit ehca_module_exit(void)
ibmebus_unregister_driver(&ehca_driver);
+ unregister_memory_notifier(&ehca_mem_nb);
+
ehca_destroy_slab_caches();
ehca_destroy_comp_pool();
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 4dbe2870e01..4d54b9f6456 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -465,9 +465,9 @@ static struct ehca_qp *internal_create_qp(
u32 swqe_size = 0, rwqe_size = 0, ib_qp_num;
unsigned long flags;
- if (!atomic_add_unless(&shca->num_qps, 1, ehca_max_qp)) {
+ if (!atomic_add_unless(&shca->num_qps, 1, shca->max_num_qps)) {
ehca_err(pd->device, "Unable to create QP, max number of %i "
- "QPs reached.", ehca_max_qp);
+ "QPs reached.", shca->max_num_qps);
ehca_err(pd->device, "To increase the maximum number of QPs "
"use the number_of_qps module parameter.\n");
return ERR_PTR(-ENOSPC);
@@ -502,6 +502,12 @@ static struct ehca_qp *internal_create_qp(
if (init_attr->srq) {
my_srq = container_of(init_attr->srq, struct ehca_qp, ib_srq);
+ if (qp_type == IB_QPT_UC) {
+ ehca_err(pd->device, "UC with SRQ not supported");
+ atomic_dec(&shca->num_qps);
+ return ERR_PTR(-EINVAL);
+ }
+
has_srq = 1;
parms.ext_type = EQPT_SRQBASE;
parms.srq_qpn = my_srq->real_qp_num;
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index cdca3a511e1..606f1e2ef28 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -298,7 +298,7 @@ int mlx4_ib_mad_init(struct mlx4_ib_dev *dev)
int p, q;
int ret;
- for (p = 0; p < dev->dev->caps.num_ports; ++p)
+ for (p = 0; p < dev->num_ports; ++p)
for (q = 0; q <= 1; ++q) {
agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
q ? IB_QPT_GSI : IB_QPT_SMI,
@@ -314,7 +314,7 @@ int mlx4_ib_mad_init(struct mlx4_ib_dev *dev)
return 0;
err:
- for (p = 0; p < dev->dev->caps.num_ports; ++p)
+ for (p = 0; p < dev->num_ports; ++p)
for (q = 0; q <= 1; ++q)
if (dev->send_agent[p][q])
ib_unregister_mad_agent(dev->send_agent[p][q]);
@@ -327,7 +327,7 @@ void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev)
struct ib_mad_agent *agent;
int p, q;
- for (p = 0; p < dev->dev->caps.num_ports; ++p) {
+ for (p = 0; p < dev->num_ports; ++p) {
for (q = 0; q <= 1; ++q) {
agent = dev->send_agent[p][q];
dev->send_agent[p][q] = NULL;
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index a3c2851c054..2e80f8f47b0 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -574,7 +574,10 @@ 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->ib_dev.phys_port_cnt = dev->caps.num_ports;
+ ibdev->num_ports = 0;
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+ ibdev->num_ports++;
+ ibdev->ib_dev.phys_port_cnt = ibdev->num_ports;
ibdev->ib_dev.num_comp_vectors = 1;
ibdev->ib_dev.dma_device = &dev->pdev->dev;
@@ -691,7 +694,7 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
struct mlx4_ib_dev *ibdev = ibdev_ptr;
int p;
- for (p = 1; p <= dev->caps.num_ports; ++p)
+ for (p = 1; p <= ibdev->num_ports; ++p)
mlx4_CLOSE_PORT(dev, p);
mlx4_ib_mad_cleanup(ibdev);
@@ -706,6 +709,10 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
enum mlx4_dev_event event, int port)
{
struct ib_event ibev;
+ struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr);
+
+ if (port > ibdev->num_ports)
+ return;
switch (event) {
case MLX4_DEV_EVENT_PORT_UP:
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 6e2b0dc21b6..9974e886b8d 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -162,6 +162,7 @@ struct mlx4_ib_ah {
struct mlx4_ib_dev {
struct ib_device ib_dev;
struct mlx4_dev *dev;
+ int num_ports;
void __iomem *uar_map;
struct mlx4_uar priv_uar;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index baa01deb243..39167a797f9 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -451,6 +451,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
struct ib_qp_init_attr *init_attr,
struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp)
{
+ int qpn;
int err;
mutex_init(&qp->mutex);
@@ -545,9 +546,17 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
}
}
- err = mlx4_qp_alloc(dev->dev, sqpn, &qp->mqp);
+ if (sqpn) {
+ qpn = sqpn;
+ } else {
+ err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn);
+ if (err)
+ goto err_wrid;
+ }
+
+ err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp);
if (err)
- goto err_wrid;
+ goto err_qpn;
/*
* Hardware wants QPN written in big-endian order (after
@@ -560,6 +569,10 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
return 0;
+err_qpn:
+ if (!sqpn)
+ mlx4_qp_release_range(dev->dev, qpn, 1);
+
err_wrid:
if (pd->uobject) {
if (!init_attr->srq)
@@ -655,6 +668,10 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
mlx4_ib_unlock_cqs(send_cq, recv_cq);
mlx4_qp_free(dev->dev, &qp->mqp);
+
+ if (!is_sqp(dev, qp))
+ mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1);
+
mlx4_mtt_cleanup(dev->dev, &qp->mtt);
if (is_user) {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 68ba5c3482e..e0c7dfabf2b 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -507,6 +507,7 @@ int ipoib_pkey_dev_delay_open(struct net_device *dev);
void ipoib_drain_cq(struct net_device *dev);
void ipoib_set_ethtool_ops(struct net_device *dev);
+int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca);
#ifdef CONFIG_INFINIBAND_IPOIB_CM
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 66af5c1a76e..e9795f60e5d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -42,6 +42,13 @@ static void ipoib_get_drvinfo(struct net_device *netdev,
strncpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver) - 1);
}
+static u32 ipoib_get_rx_csum(struct net_device *dev)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ return test_bit(IPOIB_FLAG_CSUM, &priv->flags) &&
+ !test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
+}
+
static int ipoib_get_coalesce(struct net_device *dev,
struct ethtool_coalesce *coal)
{
@@ -129,7 +136,7 @@ static void ipoib_get_ethtool_stats(struct net_device *dev,
static const struct ethtool_ops ipoib_ethtool_ops = {
.get_drvinfo = ipoib_get_drvinfo,
- .get_tso = ethtool_op_get_tso,
+ .get_rx_csum = ipoib_get_rx_csum,
.get_coalesce = ipoib_get_coalesce,
.set_coalesce = ipoib_set_coalesce,
.get_flags = ethtool_op_get_flags,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 0e748aeeae9..28eb6f03c58 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -685,10 +685,6 @@ int ipoib_ib_dev_open(struct net_device *dev)
queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
round_jiffies_relative(HZ));
- init_timer(&priv->poll_timer);
- priv->poll_timer.function = ipoib_ib_tx_timer_func;
- priv->poll_timer.data = (unsigned long)dev;
-
set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
return 0;
@@ -906,6 +902,9 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
return -ENODEV;
}
+ setup_timer(&priv->poll_timer, ipoib_ib_tx_timer_func,
+ (unsigned long) dev);
+
if (dev->flags & IFF_UP) {
if (ipoib_ib_dev_open(dev)) {
ipoib_transport_dev_cleanup(dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index c0ee514396d..fddded7900d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1173,11 +1173,48 @@ int ipoib_add_pkey_attr(struct net_device *dev)
return device_create_file(&dev->dev, &dev_attr_pkey);
}
+int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca)
+{
+ struct ib_device_attr *device_attr;
+ int result = -ENOMEM;
+
+ device_attr = kmalloc(sizeof *device_attr, GFP_KERNEL);
+ if (!device_attr) {
+ printk(KERN_WARNING "%s: allocation of %zu bytes failed\n",
+ hca->name, sizeof *device_attr);
+ return result;
+ }
+
+ result = ib_query_device(hca, device_attr);
+ if (result) {
+ printk(KERN_WARNING "%s: ib_query_device failed (ret = %d)\n",
+ hca->name, result);
+ kfree(device_attr);
+ return result;
+ }
+ priv->hca_caps = device_attr->device_cap_flags;
+
+ kfree(device_attr);
+
+ if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) {
+ set_bit(IPOIB_FLAG_CSUM, &priv->flags);
+ priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+ }
+
+ if (lro)
+ priv->dev->features |= NETIF_F_LRO;
+
+ if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO)
+ priv->dev->features |= NETIF_F_TSO;
+
+ return 0;
+}
+
+
static struct net_device *ipoib_add_port(const char *format,
struct ib_device *hca, u8 port)
{
struct ipoib_dev_priv *priv;
- struct ib_device_attr *device_attr;
struct ib_port_attr attr;
int result = -ENOMEM;
@@ -1206,31 +1243,8 @@ static struct net_device *ipoib_add_port(const char *format,
goto device_init_failed;
}
- device_attr = kmalloc(sizeof *device_attr, GFP_KERNEL);
- if (!device_attr) {
- printk(KERN_WARNING "%s: allocation of %zu bytes failed\n",
- hca->name, sizeof *device_attr);
+ if (ipoib_set_dev_features(priv, hca))
goto device_init_failed;
- }
-
- result = ib_query_device(hca, device_attr);
- if (result) {
- printk(KERN_WARNING "%s: ib_query_device failed (ret = %d)\n",
- hca->name, result);
- kfree(device_attr);
- goto device_init_failed;
- }
- priv->hca_caps = device_attr->device_cap_flags;
-
- kfree(device_attr);
-
- if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) {
- set_bit(IPOIB_FLAG_CSUM, &priv->flags);
- priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
- }
-
- if (lro)
- priv->dev->features |= NETIF_F_LRO;
/*
* Set the full membership bit, so that we join the right
@@ -1266,9 +1280,6 @@ static struct net_device *ipoib_add_port(const char *format,
goto event_failed;
}
- if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO)
- priv->dev->features |= NETIF_F_TSO;
-
result = register_netdev(priv->dev);
if (result) {
printk(KERN_WARNING "%s: couldn't register ipoib port %d; error %d\n",
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index b08eb56196d..2cf1a408871 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -93,6 +93,10 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu;
set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags);
+ result = ipoib_set_dev_features(priv, ppriv->ca);
+ if (result)
+ goto device_init_failed;
+
priv->pkey = pkey;
memcpy(priv->dev->dev_addr, ppriv->dev->dev_addr, INFINIBAND_ALEN);
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
index 7839b7b6fa9..0de9a0943a9 100644
--- a/drivers/input/joystick/iforce/iforce-ff.c
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -197,13 +197,16 @@ static unsigned char find_button(struct iforce *iforce, signed short button)
* Analyse the changes in an effect, and tell if we need to send an condition
* parameter packet
*/
-static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new)
+static int need_condition_modifier(struct iforce *iforce,
+ struct ff_effect *old,
+ struct ff_effect *new)
{
int ret = 0;
int i;
if (new->type != FF_SPRING && new->type != FF_FRICTION) {
- warn("bad effect type in need_condition_modifier");
+ dev_warn(&iforce->dev->dev, "bad effect type in %s\n",
+ __func__);
return 0;
}
@@ -222,10 +225,13 @@ static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new)
* Analyse the changes in an effect, and tell if we need to send a magnitude
* parameter packet
*/
-static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect)
+static int need_magnitude_modifier(struct iforce *iforce,
+ struct ff_effect *old,
+ struct ff_effect *effect)
{
if (effect->type != FF_CONSTANT) {
- warn("bad effect type in need_envelope_modifier");
+ dev_warn(&iforce->dev->dev, "bad effect type in %s\n",
+ __func__);
return 0;
}
@@ -236,7 +242,8 @@ static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effe
* Analyse the changes in an effect, and tell if we need to send an envelope
* parameter packet
*/
-static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effect)
+static int need_envelope_modifier(struct iforce *iforce, struct ff_effect *old,
+ struct ff_effect *effect)
{
switch (effect->type) {
case FF_CONSTANT:
@@ -256,7 +263,8 @@ static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effec
break;
default:
- warn("bad effect type in need_envelope_modifier");
+ dev_warn(&iforce->dev->dev, "bad effect type in %s\n",
+ __func__);
}
return 0;
@@ -266,10 +274,12 @@ static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effec
* Analyse the changes in an effect, and tell if we need to send a periodic
* parameter effect
*/
-static int need_period_modifier(struct ff_effect *old, struct ff_effect *new)
+static int need_period_modifier(struct iforce *iforce, struct ff_effect *old,
+ struct ff_effect *new)
{
if (new->type != FF_PERIODIC) {
- warn("bad effect type in need_period_modifier");
+ dev_warn(&iforce->dev->dev, "bad effect type in %s\n",
+ __func__);
return 0;
}
return (old->u.periodic.period != new->u.periodic.period
@@ -355,7 +365,7 @@ int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, stru
int param2_err = 1;
int core_err = 0;
- if (!old || need_period_modifier(old, effect)) {
+ if (!old || need_period_modifier(iforce, old, effect)) {
param1_err = make_period_modifier(iforce, mod1_chunk,
old != NULL,
effect->u.periodic.magnitude, effect->u.periodic.offset,
@@ -365,7 +375,7 @@ int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, stru
set_bit(FF_MOD1_IS_USED, core_effect->flags);
}
- if (!old || need_envelope_modifier(old, effect)) {
+ if (!old || need_envelope_modifier(iforce, old, effect)) {
param2_err = make_envelope_modifier(iforce, mod2_chunk,
old !=NULL,
effect->u.periodic.envelope.attack_length,
@@ -425,7 +435,7 @@ int iforce_upload_constant(struct iforce *iforce, struct ff_effect *effect, stru
int param2_err = 1;
int core_err = 0;
- if (!old || need_magnitude_modifier(old, effect)) {
+ if (!old || need_magnitude_modifier(iforce, old, effect)) {
param1_err = make_magnitude_modifier(iforce, mod1_chunk,
old != NULL,
effect->u.constant.level);
@@ -434,7 +444,7 @@ int iforce_upload_constant(struct iforce *iforce, struct ff_effect *effect, stru
set_bit(FF_MOD1_IS_USED, core_effect->flags);
}
- if (!old || need_envelope_modifier(old, effect)) {
+ if (!old || need_envelope_modifier(iforce, old, effect)) {
param2_err = make_envelope_modifier(iforce, mod2_chunk,
old != NULL,
effect->u.constant.envelope.attack_length,
@@ -487,7 +497,7 @@ int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, str
default: return -1;
}
- if (!old || need_condition_modifier(old, effect)) {
+ if (!old || need_condition_modifier(iforce, old, effect)) {
param_err = make_condition_modifier(iforce, mod1_chunk,
old != NULL,
effect->u.condition[0].right_saturation,
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 61ee6e38739..baabf830264 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -218,7 +218,9 @@ static void iforce_release(struct input_dev *dev)
/* Check: no effects should be present in memory */
for (i = 0; i < dev->ff->max_effects; i++) {
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) {
- warn("iforce_release: Device still owns effects");
+ dev_warn(&dev->dev,
+ "%s: Device still owns effects\n",
+ __func__);
break;
}
}
@@ -335,26 +337,26 @@ int iforce_init_device(struct iforce *iforce)
if (!iforce_get_id_packet(iforce, "M"))
input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
else
- warn("Device does not respond to id packet M");
+ dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");
if (!iforce_get_id_packet(iforce, "P"))
input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
else
- warn("Device does not respond to id packet P");
+ dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");
if (!iforce_get_id_packet(iforce, "B"))
iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
else
- warn("Device does not respond to id packet B");
+ dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");
if (!iforce_get_id_packet(iforce, "N"))
ff_effects = iforce->edata[1];
else
- warn("Device does not respond to id packet N");
+ dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");
/* Check if the device can store more effects than the driver can really handle */
if (ff_effects > IFORCE_EFFECTS_MAX) {
- warn("Limiting number of effects to %d (device reports %d)",
+ dev_warn(&iforce->dev->dev, "Limiting number of effects to %d (device reports %d)\n",
IFORCE_EFFECTS_MAX, ff_effects);
ff_effects = IFORCE_EFFECTS_MAX;
}
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index 015b50aa76f..a17b5001600 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -65,7 +65,8 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
- warn("not enough space in xmit buffer to send new packet");
+ dev_warn(&iforce->dev->dev,
+ "not enough space in xmit buffer to send new packet\n");
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
return -1;
}
@@ -148,7 +149,7 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
return 0;
}
}
- warn("unused effect %04x updated !!!", addr);
+ dev_warn(&iforce->dev->dev, "unused effect %04x updated !!!\n", addr);
return -1;
}
@@ -159,7 +160,8 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
static int being_used = 0;
if (being_used)
- warn("re-entrant call to iforce_process %d", being_used);
+ dev_warn(&iforce->dev->dev,
+ "re-entrant call to iforce_process %d\n", being_used);
being_used++;
#ifdef CONFIG_JOYSTICK_IFORCE_232
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 851cc4087c2..f83185aeb51 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -64,7 +64,7 @@ void iforce_usb_xmit(struct iforce *iforce)
if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
- warn("usb_submit_urb failed %d\n", n);
+ dev_warn(&iforce->dev->dev, "usb_submit_urb failed %d\n", n);
}
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 839d1c9622f..b868b8d5fbb 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -911,7 +911,7 @@ static int __init usb_xpad_init(void)
{
int result = usb_register(&xpad_driver);
if (result == 0)
- info(DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return result;
}
diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c
index debfc1af9d9..e290fde35e7 100644
--- a/drivers/input/misc/ati_remote.c
+++ b/drivers/input/misc/ati_remote.c
@@ -285,7 +285,6 @@ static const struct {
};
/* Local function prototypes */
-static void ati_remote_dump (unsigned char *data, unsigned int actual_length);
static int ati_remote_open (struct input_dev *inputdev);
static void ati_remote_close (struct input_dev *inputdev);
static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
@@ -307,15 +306,16 @@ static struct usb_driver ati_remote_driver = {
/*
* ati_remote_dump_input
*/
-static void ati_remote_dump(unsigned char *data, unsigned int len)
+static void ati_remote_dump(struct device *dev, unsigned char *data,
+ unsigned int len)
{
if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
- warn("Weird byte 0x%02x", data[0]);
+ dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
else if (len == 4)
- warn("Weird key %02x %02x %02x %02x",
+ dev_warn(dev, "Weird key %02x %02x %02x %02x\n",
data[0], data[1], data[2], data[3]);
else
- warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
+ dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
len, data[0], data[1], data[2], data[3], data[4], data[5]);
}
@@ -470,7 +470,7 @@ static void ati_remote_input_report(struct urb *urb)
/* Deal with strange looking inputs */
if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
((data[3] & 0x0f) != 0x00) ) {
- ati_remote_dump(data, urb->actual_length);
+ ati_remote_dump(&urb->dev->dev, data, urb->actual_length);
return;
}
@@ -814,7 +814,7 @@ static void ati_remote_disconnect(struct usb_interface *interface)
ati_remote = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
if (!ati_remote) {
- warn("%s - null device?\n", __func__);
+ dev_warn(&interface->dev, "%s - null device?\n", __func__);
return;
}
@@ -834,9 +834,11 @@ static int __init ati_remote_init(void)
result = usb_register(&ati_remote_driver);
if (result)
- err("usb_register error #%d\n", result);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": usb_register error #%d\n", result);
else
- info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return result;
}
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index 11b5c7e84ed..93a22ac0f88 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -999,7 +999,8 @@ static int __init yealink_dev_init(void)
{
int ret = usb_register(&yealink_driver);
if (ret == 0)
- info(DRIVER_DESC ":" DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return ret;
}
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
index 570e0e83ac4..670c61c5a51 100644
--- a/drivers/input/tablet/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -280,7 +280,8 @@ static int __init usb_acecad_init(void)
{
int result = usb_register(&usb_acecad_driver);
if (result == 0)
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return result;
}
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index e53c838f186..7d005a3616d 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -1706,20 +1706,21 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL);
inputdev = input_allocate_device();
if (!aiptek || !inputdev) {
- warn("aiptek: cannot allocate memory or input device");
+ dev_warn(&intf->dev,
+ "cannot allocate memory or input device\n");
goto fail1;
}
aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH,
GFP_ATOMIC, &aiptek->data_dma);
if (!aiptek->data) {
- warn("aiptek: cannot allocate usb buffer");
+ dev_warn(&intf->dev, "cannot allocate usb buffer\n");
goto fail1;
}
aiptek->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!aiptek->urb) {
- warn("aiptek: cannot allocate urb");
+ dev_warn(&intf->dev, "cannot allocate urb\n");
goto fail2;
}
@@ -1843,8 +1844,9 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
aiptek->curSetting.programmableDelay = speeds[i];
(void)aiptek_program_tablet(aiptek);
if (aiptek->inputdev->absmax[ABS_X] > 0) {
- info("input: Aiptek using %d ms programming speed\n",
- aiptek->curSetting.programmableDelay);
+ dev_info(&intf->dev,
+ "Aiptek using %d ms programming speed\n",
+ aiptek->curSetting.programmableDelay);
break;
}
}
@@ -1852,7 +1854,8 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* Murphy says that some day someone will have a tablet that fails the
above test. That's you, Frederic Rodrigo */
if (i == ARRAY_SIZE(speeds)) {
- info("input: Aiptek tried all speeds, no sane response");
+ dev_info(&intf->dev,
+ "Aiptek tried all speeds, no sane response\n");
goto fail2;
}
@@ -1864,7 +1867,8 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
*/
err = sysfs_create_group(&intf->dev.kobj, &aiptek_attribute_group);
if (err) {
- warn("aiptek: cannot create sysfs group err: %d", err);
+ dev_warn(&intf->dev, "cannot create sysfs group err: %d\n",
+ err);
goto fail3;
}
@@ -1872,7 +1876,8 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
*/
err = input_register_device(aiptek->inputdev);
if (err) {
- warn("aiptek: input_register_device returned err: %d", err);
+ dev_warn(&intf->dev,
+ "input_register_device returned err: %d\n", err);
goto fail4;
}
return 0;
@@ -1922,8 +1927,9 @@ static int __init aiptek_init(void)
{
int result = usb_register(&aiptek_driver);
if (result == 0) {
- info(DRIVER_VERSION ": " DRIVER_AUTHOR);
- info(DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_AUTHOR "\n");
}
return result;
}
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 7df0228e836..5524e01dbb1 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -2,7 +2,7 @@
GTCO digitizer USB driver
-Use the err(), dbg() and info() macros from usb.h for system logging
+Use the err() and dbg() macros from usb.h for system logging
TO CHECK: Is pressure done right on report 5?
@@ -1010,7 +1010,7 @@ static void gtco_disconnect(struct usb_interface *interface)
kfree(gtco);
}
- info("gtco driver disconnected");
+ dev_info(&interface->dev, "gtco driver disconnected\n");
}
/* STANDARD MODULE LOAD ROUTINES */
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index d89112fa6e6..6682b17bf84 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -215,7 +215,8 @@ static int __init kbtab_init(void)
retval = usb_register(&kbtab_driver);
if (retval)
goto out;
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
out:
return retval;
}
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 5fbc463baf5..09e227aa0d4 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -385,7 +385,8 @@ static int __init wacom_init(void)
wacom_driver.id_table = get_device_table();
result = usb_register(&wacom_driver);
if (result == 0)
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return result;
}
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6e1e8c624f9..8317fdef169 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -219,7 +219,7 @@ config TOUCHSCREEN_ATMEL_TSADCC
config TOUCHSCREEN_UCB1400
tristate "Philips UCB1400 touchscreen"
- select AC97_BUS
+ depends on AC97_BUS
depends on UCB1400_CORE
help
This enables support for the Philips UCB1400 touchscreen interface.
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index c38d4e0f95c..a89700e7ace 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -5,7 +5,7 @@
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/adc.h>
-#include <asm/hp6xx.h>
+#include <mach/hp6xx.h>
#define MODNAME "hp680_ts_input"
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index e3e40427e00..c7ff1e11ea8 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -179,7 +179,7 @@ config LEDS_TRIGGER_TIMER
config LEDS_TRIGGER_IDE_DISK
bool "LED IDE Disk Trigger"
- depends on LEDS_TRIGGERS && BLK_DEV_IDEDISK
+ depends on LEDS_TRIGGERS && IDE_GD_ATA
help
This allows LEDs to be controlled by IDE disk activity.
If unsure, say Y.
diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c
index 844d5979c90..e8fb1baf8a5 100644
--- a/drivers/leds/leds-hp6xx.c
+++ b/drivers/leds/leds-hp6xx.c
@@ -15,7 +15,7 @@
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <asm/hd64461.h>
-#include <asm/hp6xx.h>
+#include <mach/hp6xx.h>
static void hp6xxled_green_set(struct led_classdev *led_cdev,
enum led_brightness value)
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index f1ef33dfd8c..1c615804ea7 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
obj-$(CONFIG_DM_DELAY) += dm-delay.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
-obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o
+obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o
quiet_cmd_unroll = UNROLL $@
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 682ef9e6acd..ce26c84af06 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -23,7 +23,7 @@
#include <asm/page.h>
#include <asm/unaligned.h>
-#include "dm.h"
+#include <linux/device-mapper.h>
#define DM_MSG_PREFIX "crypt"
#define MESG_STR(x) x, sizeof(x)
@@ -56,6 +56,7 @@ struct dm_crypt_io {
atomic_t pending;
int error;
sector_t sector;
+ struct dm_crypt_io *base_io;
};
struct dm_crypt_request {
@@ -93,7 +94,6 @@ struct crypt_config {
struct workqueue_struct *io_queue;
struct workqueue_struct *crypt_queue;
- wait_queue_head_t writeq;
/*
* crypto related data
@@ -534,6 +534,7 @@ static struct dm_crypt_io *crypt_io_alloc(struct dm_target *ti,
io->base_bio = bio;
io->sector = sector;
io->error = 0;
+ io->base_io = NULL;
atomic_set(&io->pending, 0);
return io;
@@ -547,6 +548,7 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
/*
* One of the bios was finished. Check for completion of
* the whole request and correctly clean up the buffer.
+ * If base_io is set, wait for the last fragment to complete.
*/
static void crypt_dec_pending(struct dm_crypt_io *io)
{
@@ -555,7 +557,14 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
if (!atomic_dec_and_test(&io->pending))
return;
- bio_endio(io->base_bio, io->error);
+ if (likely(!io->base_io))
+ bio_endio(io->base_bio, io->error);
+ else {
+ if (io->error && !io->base_io->error)
+ io->base_io->error = io->error;
+ crypt_dec_pending(io->base_io);
+ }
+
mempool_free(io, cc->io_pool);
}
@@ -646,10 +655,7 @@ static void kcryptd_io_read(struct dm_crypt_io *io)
static void kcryptd_io_write(struct dm_crypt_io *io)
{
struct bio *clone = io->ctx.bio_out;
- struct crypt_config *cc = io->target->private;
-
generic_make_request(clone);
- wake_up(&cc->writeq);
}
static void kcryptd_io(struct work_struct *work)
@@ -688,7 +694,6 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io,
BUG_ON(io->ctx.idx_out < clone->bi_vcnt);
clone->bi_sector = cc->start + io->sector;
- io->sector += bio_sectors(clone);
if (async)
kcryptd_queue_io(io);
@@ -700,16 +705,18 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->target->private;
struct bio *clone;
+ struct dm_crypt_io *new_io;
int crypt_finished;
unsigned out_of_pages = 0;
unsigned remaining = io->base_bio->bi_size;
+ sector_t sector = io->sector;
int r;
/*
* Prevent io from disappearing until this function completes.
*/
crypt_inc_pending(io);
- crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, io->sector);
+ crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, sector);
/*
* The allocated buffers can be smaller than the whole bio,
@@ -726,6 +733,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
io->ctx.idx_out = 0;
remaining -= clone->bi_size;
+ sector += bio_sectors(clone);
crypt_inc_pending(io);
r = crypt_convert(cc, &io->ctx);
@@ -741,6 +749,8 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
*/
if (unlikely(r < 0))
break;
+
+ io->sector = sector;
}
/*
@@ -750,8 +760,33 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
if (unlikely(out_of_pages))
congestion_wait(WRITE, HZ/100);
- if (unlikely(remaining))
- wait_event(cc->writeq, !atomic_read(&io->ctx.pending));
+ /*
+ * With async crypto it is unsafe to share the crypto context
+ * between fragments, so switch to a new dm_crypt_io structure.
+ */
+ if (unlikely(!crypt_finished && remaining)) {
+ new_io = crypt_io_alloc(io->target, io->base_bio,
+ sector);
+ crypt_inc_pending(new_io);
+ crypt_convert_init(cc, &new_io->ctx, NULL,
+ io->base_bio, sector);
+ new_io->ctx.idx_in = io->ctx.idx_in;
+ new_io->ctx.offset_in = io->ctx.offset_in;
+
+ /*
+ * Fragments after the first use the base_io
+ * pending count.
+ */
+ if (!io->base_io)
+ new_io->base_io = io;
+ else {
+ new_io->base_io = io->base_io;
+ crypt_inc_pending(io->base_io);
+ crypt_dec_pending(io);
+ }
+
+ io = new_io;
+ }
}
crypt_dec_pending(io);
@@ -1078,7 +1113,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad_crypt_queue;
}
- init_waitqueue_head(&cc->writeq);
ti->private = cc;
return 0;
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index bdd37f881c4..848b381f117 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -13,7 +13,8 @@
#include <linux/bio.h>
#include <linux/slab.h>
-#include "dm.h"
+#include <linux/device-mapper.h>
+
#include "dm-bio-list.h"
#define DM_MSG_PREFIX "delay"
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 769ab677f8e..01590f3e000 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -7,7 +7,6 @@
* This file is released under the GPL.
*/
-#include "dm.h"
#include "dm-snap.h"
#include <linux/mm.h>
@@ -105,6 +104,11 @@ struct pstore {
void *area;
/*
+ * An area of zeros used to clear the next area.
+ */
+ void *zero_area;
+
+ /*
* Used to keep track of which metadata area the data in
* 'chunk' refers to.
*/
@@ -149,6 +153,13 @@ static int alloc_area(struct pstore *ps)
if (!ps->area)
return r;
+ ps->zero_area = vmalloc(len);
+ if (!ps->zero_area) {
+ vfree(ps->area);
+ return r;
+ }
+ memset(ps->zero_area, 0, len);
+
return 0;
}
@@ -156,6 +167,8 @@ static void free_area(struct pstore *ps)
{
vfree(ps->area);
ps->area = NULL;
+ vfree(ps->zero_area);
+ ps->zero_area = NULL;
}
struct mdata_req {
@@ -220,25 +233,41 @@ static chunk_t area_location(struct pstore *ps, chunk_t area)
* Read or write a metadata area. Remembering to skip the first
* chunk which holds the header.
*/
-static int area_io(struct pstore *ps, chunk_t area, int rw)
+static int area_io(struct pstore *ps, int rw)
{
int r;
chunk_t chunk;
- chunk = area_location(ps, area);
+ chunk = area_location(ps, ps->current_area);
r = chunk_io(ps, chunk, rw, 0);
if (r)
return r;
- ps->current_area = area;
return 0;
}
-static int zero_area(struct pstore *ps, chunk_t area)
+static void zero_memory_area(struct pstore *ps)
{
memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
- return area_io(ps, area, WRITE);
+}
+
+static int zero_disk_area(struct pstore *ps, chunk_t area)
+{
+ struct dm_io_region where = {
+ .bdev = ps->snap->cow->bdev,
+ .sector = ps->snap->chunk_size * area_location(ps, area),
+ .count = ps->snap->chunk_size,
+ };
+ struct dm_io_request io_req = {
+ .bi_rw = WRITE,
+ .mem.type = DM_IO_VMA,
+ .mem.ptr.vma = ps->zero_area,
+ .client = ps->io_client,
+ .notify.fn = NULL,
+ };
+
+ return dm_io(&io_req, 1, &where, NULL);
}
static int read_header(struct pstore *ps, int *new_snapshot)
@@ -411,15 +440,14 @@ static int insert_exceptions(struct pstore *ps, int *full)
static int read_exceptions(struct pstore *ps)
{
- chunk_t area;
int r, full = 1;
/*
* Keeping reading chunks and inserting exceptions until
* we find a partially full area.
*/
- for (area = 0; full; area++) {
- r = area_io(ps, area, READ);
+ for (ps->current_area = 0; full; ps->current_area++) {
+ r = area_io(ps, READ);
if (r)
return r;
@@ -428,6 +456,8 @@ static int read_exceptions(struct pstore *ps)
return r;
}
+ ps->current_area--;
+
return 0;
}
@@ -486,12 +516,13 @@ static int persistent_read_metadata(struct exception_store *store)
return r;
}
- r = zero_area(ps, 0);
+ ps->current_area = 0;
+ zero_memory_area(ps);
+ r = zero_disk_area(ps, 0);
if (r) {
- DMWARN("zero_area(0) failed");
+ DMWARN("zero_disk_area(0) failed");
return r;
}
-
} else {
/*
* Sanity checks.
@@ -551,7 +582,6 @@ static void persistent_commit(struct exception_store *store,
void (*callback) (void *, int success),
void *callback_context)
{
- int r;
unsigned int i;
struct pstore *ps = get_info(store);
struct disk_exception de;
@@ -572,33 +602,41 @@ static void persistent_commit(struct exception_store *store,
cb->context = callback_context;
/*
- * If there are no more exceptions in flight, or we have
- * filled this metadata area we commit the exceptions to
- * disk.
+ * If there are exceptions in flight and we have not yet
+ * filled this metadata area there's nothing more to do.
*/
- if (atomic_dec_and_test(&ps->pending_count) ||
- (ps->current_committed == ps->exceptions_per_area)) {
- r = area_io(ps, ps->current_area, WRITE);
- if (r)
- ps->valid = 0;
+ if (!atomic_dec_and_test(&ps->pending_count) &&
+ (ps->current_committed != ps->exceptions_per_area))
+ return;
- /*
- * Have we completely filled the current area ?
- */
- if (ps->current_committed == ps->exceptions_per_area) {
- ps->current_committed = 0;
- r = zero_area(ps, ps->current_area + 1);
- if (r)
- ps->valid = 0;
- }
+ /*
+ * If we completely filled the current area, then wipe the next one.
+ */
+ if ((ps->current_committed == ps->exceptions_per_area) &&
+ zero_disk_area(ps, ps->current_area + 1))
+ ps->valid = 0;
- for (i = 0; i < ps->callback_count; i++) {
- cb = ps->callbacks + i;
- cb->callback(cb->context, r == 0 ? 1 : 0);
- }
+ /*
+ * Commit exceptions to disk.
+ */
+ if (ps->valid && area_io(ps, WRITE))
+ ps->valid = 0;
- ps->callback_count = 0;
+ /*
+ * Advance to the next area if this one is full.
+ */
+ if (ps->current_committed == ps->exceptions_per_area) {
+ ps->current_committed = 0;
+ ps->current_area++;
+ zero_memory_area(ps);
}
+
+ for (i = 0; i < ps->callback_count; i++) {
+ cb = ps->callbacks + i;
+ cb->callback(cb->context, ps->valid);
+ }
+
+ ps->callback_count = 0;
}
static void persistent_drop(struct exception_store *store)
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 4789c42d9a3..2fd6d445063 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -5,7 +5,7 @@
* This file is released under the GPL.
*/
-#include "dm.h"
+#include <linux/device-mapper.h>
#include <linux/bio.h>
#include <linux/mempool.h>
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index dca401dc70a..777c948180f 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -988,9 +988,9 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
return r;
}
-static inline int get_mode(struct dm_ioctl *param)
+static inline fmode_t get_mode(struct dm_ioctl *param)
{
- int mode = FMODE_READ | FMODE_WRITE;
+ fmode_t mode = FMODE_READ | FMODE_WRITE;
if (param->flags & DM_READONLY_FLAG)
mode = FMODE_READ;
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c
index 996802b8a45..3073618269e 100644
--- a/drivers/md/dm-kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -22,6 +22,7 @@
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
+#include <linux/device-mapper.h>
#include <linux/dm-kcopyd.h>
#include "dm.h"
@@ -268,6 +269,17 @@ static void push(struct list_head *jobs, struct kcopyd_job *job)
spin_unlock_irqrestore(&kc->job_lock, flags);
}
+
+static void push_head(struct list_head *jobs, struct kcopyd_job *job)
+{
+ unsigned long flags;
+ struct dm_kcopyd_client *kc = job->kc;
+
+ spin_lock_irqsave(&kc->job_lock, flags);
+ list_add(&job->list, jobs);
+ spin_unlock_irqrestore(&kc->job_lock, flags);
+}
+
/*
* These three functions process 1 item from the corresponding
* job list.
@@ -398,7 +410,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
* We couldn't service this job ATM, so
* push this job back onto the list.
*/
- push(jobs, job);
+ push_head(jobs, job);
break;
}
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 6449bcdf84c..44042becad8 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -5,12 +5,12 @@
*/
#include "dm.h"
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
#include <linux/slab.h>
+#include <linux/device-mapper.h>
#define DM_MSG_PREFIX "linear"
@@ -110,20 +110,11 @@ static int linear_status(struct dm_target *ti, status_type_t type,
return 0;
}
-static int linear_ioctl(struct dm_target *ti, struct inode *inode,
- struct file *filp, unsigned int cmd,
+static int linear_ioctl(struct dm_target *ti, unsigned int cmd,
unsigned long arg)
{
struct linear_c *lc = (struct linear_c *) ti->private;
- struct block_device *bdev = lc->dev->bdev;
- struct file fake_file = {};
- struct dentry fake_dentry = {};
-
- fake_file.f_mode = lc->dev->mode;
- fake_file.f_path.dentry = &fake_dentry;
- fake_dentry.d_inode = bdev->bd_inode;
-
- return blkdev_driver_ioctl(bdev->bd_inode, &fake_file, bdev->bd_disk, cmd, arg);
+ return __blkdev_driver_ioctl(lc->dev->bdev, lc->dev->mode, cmd, arg);
}
static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 5b48478c79f..a8c0fc79ca7 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -12,7 +12,7 @@
#include <linux/dm-io.h>
#include <linux/dm-dirty-log.h>
-#include "dm.h"
+#include <linux/device-mapper.h>
#define DM_MSG_PREFIX "dirty region log"
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 9bf3460c554..4840733cd90 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -5,7 +5,8 @@
* This file is released under the GPL.
*/
-#include "dm.h"
+#include <linux/device-mapper.h>
+
#include "dm-path-selector.h"
#include "dm-bio-list.h"
#include "dm-bio-record.h"
@@ -1395,19 +1396,15 @@ error:
return -EINVAL;
}
-static int multipath_ioctl(struct dm_target *ti, struct inode *inode,
- struct file *filp, unsigned int cmd,
+static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
unsigned long arg)
{
struct multipath *m = (struct multipath *) ti->private;
struct block_device *bdev = NULL;
+ fmode_t mode = 0;
unsigned long flags;
- struct file fake_file = {};
- struct dentry fake_dentry = {};
int r = 0;
- fake_file.f_path.dentry = &fake_dentry;
-
spin_lock_irqsave(&m->lock, flags);
if (!m->current_pgpath)
@@ -1415,8 +1412,7 @@ static int multipath_ioctl(struct dm_target *ti, struct inode *inode,
if (m->current_pgpath) {
bdev = m->current_pgpath->path.dev->bdev;
- fake_dentry.d_inode = bdev->bd_inode;
- fake_file.f_mode = m->current_pgpath->path.dev->mode;
+ mode = m->current_pgpath->path.dev->mode;
}
if (m->queue_io)
@@ -1426,8 +1422,7 @@ static int multipath_ioctl(struct dm_target *ti, struct inode *inode,
spin_unlock_irqrestore(&m->lock, flags);
- return r ? : blkdev_driver_ioctl(bdev->bd_inode, &fake_file,
- bdev->bd_disk, cmd, arg);
+ return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
}
/*-----------------------------------------------------------------
diff --git a/drivers/md/dm-path-selector.c b/drivers/md/dm-path-selector.c
index ca1bb636a3e..96ea226155b 100644
--- a/drivers/md/dm-path-selector.c
+++ b/drivers/md/dm-path-selector.c
@@ -9,7 +9,8 @@
* Path selector registration.
*/
-#include "dm.h"
+#include <linux/device-mapper.h>
+
#include "dm-path-selector.h"
#include <linux/slab.h>
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 29913e42c4a..92dcc06832a 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1,30 +1,30 @@
/*
* Copyright (C) 2003 Sistina Software Limited.
+ * Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved.
*
* This file is released under the GPL.
*/
-#include "dm.h"
#include "dm-bio-list.h"
#include "dm-bio-record.h"
-#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/mempool.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/vmalloc.h>
#include <linux/workqueue.h>
-#include <linux/log2.h>
-#include <linux/hardirq.h>
+#include <linux/device-mapper.h>
#include <linux/dm-io.h>
#include <linux/dm-dirty-log.h>
#include <linux/dm-kcopyd.h>
+#include <linux/dm-region-hash.h>
#define DM_MSG_PREFIX "raid1"
+
+#define MAX_RECOVERY 1 /* Maximum number of regions recovered in parallel. */
#define DM_IO_PAGES 64
+#define DM_KCOPYD_PAGES 64
#define DM_RAID1_HANDLE_ERRORS 0x01
#define errors_handled(p) ((p)->features & DM_RAID1_HANDLE_ERRORS)
@@ -32,87 +32,6 @@
static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
/*-----------------------------------------------------------------
- * Region hash
- *
- * The mirror splits itself up into discrete regions. Each
- * region can be in one of three states: clean, dirty,
- * nosync. There is no need to put clean regions in the hash.
- *
- * In addition to being present in the hash table a region _may_
- * be present on one of three lists.
- *
- * clean_regions: Regions on this list have no io pending to
- * them, they are in sync, we are no longer interested in them,
- * they are dull. rh_update_states() will remove them from the
- * hash table.
- *
- * quiesced_regions: These regions have been spun down, ready
- * for recovery. rh_recovery_start() will remove regions from
- * this list and hand them to kmirrord, which will schedule the
- * recovery io with kcopyd.
- *
- * recovered_regions: Regions that kcopyd has successfully
- * recovered. rh_update_states() will now schedule any delayed
- * io, up the recovery_count, and remove the region from the
- * hash.
- *
- * There are 2 locks:
- * A rw spin lock 'hash_lock' protects just the hash table,
- * this is never held in write mode from interrupt context,
- * which I believe means that we only have to disable irqs when
- * doing a write lock.
- *
- * An ordinary spin lock 'region_lock' that protects the three
- * lists in the region_hash, with the 'state', 'list' and
- * 'bhs_delayed' fields of the regions. This is used from irq
- * context, so all other uses will have to suspend local irqs.
- *---------------------------------------------------------------*/
-struct mirror_set;
-struct region_hash {
- struct mirror_set *ms;
- uint32_t region_size;
- unsigned region_shift;
-
- /* holds persistent region state */
- struct dm_dirty_log *log;
-
- /* hash table */
- rwlock_t hash_lock;
- mempool_t *region_pool;
- unsigned int mask;
- unsigned int nr_buckets;
- struct list_head *buckets;
-
- spinlock_t region_lock;
- atomic_t recovery_in_flight;
- struct semaphore recovery_count;
- struct list_head clean_regions;
- struct list_head quiesced_regions;
- struct list_head recovered_regions;
- struct list_head failed_recovered_regions;
-};
-
-enum {
- RH_CLEAN,
- RH_DIRTY,
- RH_NOSYNC,
- RH_RECOVERING
-};
-
-struct region {
- struct region_hash *rh; /* FIXME: can we get rid of this ? */
- region_t key;
- int state;
-
- struct list_head hash_list;
- struct list_head list;
-
- atomic_t pending;
- struct bio_list delayed_bios;
-};
-
-
-/*-----------------------------------------------------------------
* Mirror set structures.
*---------------------------------------------------------------*/
enum dm_raid1_error {
@@ -132,8 +51,7 @@ struct mirror {
struct mirror_set {
struct dm_target *ti;
struct list_head list;
- struct region_hash rh;
- struct dm_kcopyd_client *kcopyd_client;
+
uint64_t features;
spinlock_t lock; /* protects the lists */
@@ -141,6 +59,8 @@ struct mirror_set {
struct bio_list writes;
struct bio_list failures;
+ struct dm_region_hash *rh;
+ struct dm_kcopyd_client *kcopyd_client;
struct dm_io_client *io_client;
mempool_t *read_record_pool;
@@ -159,25 +79,14 @@ struct mirror_set {
struct work_struct trigger_event;
- unsigned int nr_mirrors;
+ unsigned nr_mirrors;
struct mirror mirror[0];
};
-/*
- * Conversion fns
- */
-static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio)
-{
- return (bio->bi_sector - rh->ms->ti->begin) >> rh->region_shift;
-}
-
-static inline sector_t region_to_sector(struct region_hash *rh, region_t region)
+static void wakeup_mirrord(void *context)
{
- return region << rh->region_shift;
-}
+ struct mirror_set *ms = context;
-static void wake(struct mirror_set *ms)
-{
queue_work(ms->kmirrord_wq, &ms->kmirrord_work);
}
@@ -186,7 +95,7 @@ static void delayed_wake_fn(unsigned long data)
struct mirror_set *ms = (struct mirror_set *) data;
clear_bit(0, &ms->timer_pending);
- wake(ms);
+ wakeup_mirrord(ms);
}
static void delayed_wake(struct mirror_set *ms)
@@ -200,473 +109,34 @@ static void delayed_wake(struct mirror_set *ms)
add_timer(&ms->timer);
}
-/* FIXME move this */
-static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
-
-#define MIN_REGIONS 64
-#define MAX_RECOVERY 1
-static int rh_init(struct region_hash *rh, struct mirror_set *ms,
- struct dm_dirty_log *log, uint32_t region_size,
- region_t nr_regions)
+static void wakeup_all_recovery_waiters(void *context)
{
- unsigned int nr_buckets, max_buckets;
- size_t i;
-
- /*
- * Calculate a suitable number of buckets for our hash
- * table.
- */
- max_buckets = nr_regions >> 6;
- for (nr_buckets = 128u; nr_buckets < max_buckets; nr_buckets <<= 1)
- ;
- nr_buckets >>= 1;
-
- rh->ms = ms;
- rh->log = log;
- rh->region_size = region_size;
- rh->region_shift = ffs(region_size) - 1;
- rwlock_init(&rh->hash_lock);
- rh->mask = nr_buckets - 1;
- rh->nr_buckets = nr_buckets;
-
- rh->buckets = vmalloc(nr_buckets * sizeof(*rh->buckets));
- if (!rh->buckets) {
- DMERR("unable to allocate region hash memory");
- return -ENOMEM;
- }
-
- for (i = 0; i < nr_buckets; i++)
- INIT_LIST_HEAD(rh->buckets + i);
-
- spin_lock_init(&rh->region_lock);
- sema_init(&rh->recovery_count, 0);
- atomic_set(&rh->recovery_in_flight, 0);
- INIT_LIST_HEAD(&rh->clean_regions);
- INIT_LIST_HEAD(&rh->quiesced_regions);
- INIT_LIST_HEAD(&rh->recovered_regions);
- INIT_LIST_HEAD(&rh->failed_recovered_regions);
-
- rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS,
- sizeof(struct region));
- if (!rh->region_pool) {
- vfree(rh->buckets);
- rh->buckets = NULL;
- return -ENOMEM;
- }
-
- return 0;
+ wake_up_all(&_kmirrord_recovery_stopped);
}
-static void rh_exit(struct region_hash *rh)
-{
- unsigned int h;
- struct region *reg, *nreg;
-
- BUG_ON(!list_empty(&rh->quiesced_regions));
- for (h = 0; h < rh->nr_buckets; h++) {
- list_for_each_entry_safe(reg, nreg, rh->buckets + h, hash_list) {
- BUG_ON(atomic_read(&reg->pending));
- mempool_free(reg, rh->region_pool);
- }
- }
-
- if (rh->log)
- dm_dirty_log_destroy(rh->log);
- if (rh->region_pool)
- mempool_destroy(rh->region_pool);
- vfree(rh->buckets);
-}
-
-#define RH_HASH_MULT 2654435387U
-
-static inline unsigned int rh_hash(struct region_hash *rh, region_t region)
-{
- return (unsigned int) ((region * RH_HASH_MULT) >> 12) & rh->mask;
-}
-
-static struct region *__rh_lookup(struct region_hash *rh, region_t region)
-{
- struct region *reg;
-
- list_for_each_entry (reg, rh->buckets + rh_hash(rh, region), hash_list)
- if (reg->key == region)
- return reg;
-
- return NULL;
-}
-
-static void __rh_insert(struct region_hash *rh, struct region *reg)
-{
- unsigned int h = rh_hash(rh, reg->key);
- list_add(&reg->hash_list, rh->buckets + h);
-}
-
-static struct region *__rh_alloc(struct region_hash *rh, region_t region)
-{
- struct region *reg, *nreg;
-
- read_unlock(&rh->hash_lock);
- nreg = mempool_alloc(rh->region_pool, GFP_ATOMIC);
- if (unlikely(!nreg))
- nreg = kmalloc(sizeof(struct region), GFP_NOIO);
- nreg->state = rh->log->type->in_sync(rh->log, region, 1) ?
- RH_CLEAN : RH_NOSYNC;
- nreg->rh = rh;
- nreg->key = region;
-
- INIT_LIST_HEAD(&nreg->list);
-
- atomic_set(&nreg->pending, 0);
- bio_list_init(&nreg->delayed_bios);
- write_lock_irq(&rh->hash_lock);
-
- reg = __rh_lookup(rh, region);
- if (reg)
- /* we lost the race */
- mempool_free(nreg, rh->region_pool);
-
- else {
- __rh_insert(rh, nreg);
- if (nreg->state == RH_CLEAN) {
- spin_lock(&rh->region_lock);
- list_add(&nreg->list, &rh->clean_regions);
- spin_unlock(&rh->region_lock);
- }
- reg = nreg;
- }
- write_unlock_irq(&rh->hash_lock);
- read_lock(&rh->hash_lock);
-
- return reg;
-}
-
-static inline struct region *__rh_find(struct region_hash *rh, region_t region)
-{
- struct region *reg;
-
- reg = __rh_lookup(rh, region);
- if (!reg)
- reg = __rh_alloc(rh, region);
-
- return reg;
-}
-
-static int rh_state(struct region_hash *rh, region_t region, int may_block)
-{
- int r;
- struct region *reg;
-
- read_lock(&rh->hash_lock);
- reg = __rh_lookup(rh, region);
- read_unlock(&rh->hash_lock);
-
- if (reg)
- return reg->state;
-
- /*
- * The region wasn't in the hash, so we fall back to the
- * dirty log.
- */
- r = rh->log->type->in_sync(rh->log, region, may_block);
-
- /*
- * Any error from the dirty log (eg. -EWOULDBLOCK) gets
- * taken as a RH_NOSYNC
- */
- return r == 1 ? RH_CLEAN : RH_NOSYNC;
-}
-
-static inline int rh_in_sync(struct region_hash *rh,
- region_t region, int may_block)
-{
- int state = rh_state(rh, region, may_block);
- return state == RH_CLEAN || state == RH_DIRTY;
-}
-
-static void dispatch_bios(struct mirror_set *ms, struct bio_list *bio_list)
-{
- struct bio *bio;
-
- while ((bio = bio_list_pop(bio_list))) {
- queue_bio(ms, bio, WRITE);
- }
-}
-
-static void complete_resync_work(struct region *reg, int success)
-{
- struct region_hash *rh = reg->rh;
-
- rh->log->type->set_region_sync(rh->log, reg->key, success);
-
- /*
- * Dispatch the bios before we call 'wake_up_all'.
- * This is important because if we are suspending,
- * we want to know that recovery is complete and
- * the work queue is flushed. If we wake_up_all
- * before we dispatch_bios (queue bios and call wake()),
- * then we risk suspending before the work queue
- * has been properly flushed.
- */
- dispatch_bios(rh->ms, &reg->delayed_bios);
- if (atomic_dec_and_test(&rh->recovery_in_flight))
- wake_up_all(&_kmirrord_recovery_stopped);
- up(&rh->recovery_count);
-}
-
-static void rh_update_states(struct region_hash *rh)
-{
- struct region *reg, *next;
-
- LIST_HEAD(clean);
- LIST_HEAD(recovered);
- LIST_HEAD(failed_recovered);
-
- /*
- * Quickly grab the lists.
- */
- write_lock_irq(&rh->hash_lock);
- spin_lock(&rh->region_lock);
- if (!list_empty(&rh->clean_regions)) {
- list_splice_init(&rh->clean_regions, &clean);
-
- list_for_each_entry(reg, &clean, list)
- list_del(&reg->hash_list);
- }
-
- if (!list_empty(&rh->recovered_regions)) {
- list_splice_init(&rh->recovered_regions, &recovered);
-
- list_for_each_entry (reg, &recovered, list)
- list_del(&reg->hash_list);
- }
-
- if (!list_empty(&rh->failed_recovered_regions)) {
- list_splice_init(&rh->failed_recovered_regions,
- &failed_recovered);
-
- list_for_each_entry(reg, &failed_recovered, list)
- list_del(&reg->hash_list);
- }
-
- spin_unlock(&rh->region_lock);
- write_unlock_irq(&rh->hash_lock);
-
- /*
- * All the regions on the recovered and clean lists have
- * now been pulled out of the system, so no need to do
- * any more locking.
- */
- list_for_each_entry_safe (reg, next, &recovered, list) {
- rh->log->type->clear_region(rh->log, reg->key);
- complete_resync_work(reg, 1);
- mempool_free(reg, rh->region_pool);
- }
-
- list_for_each_entry_safe(reg, next, &failed_recovered, list) {
- complete_resync_work(reg, errors_handled(rh->ms) ? 0 : 1);
- mempool_free(reg, rh->region_pool);
- }
-
- list_for_each_entry_safe(reg, next, &clean, list) {
- rh->log->type->clear_region(rh->log, reg->key);
- mempool_free(reg, rh->region_pool);
- }
-
- rh->log->type->flush(rh->log);
-}
-
-static void rh_inc(struct region_hash *rh, region_t region)
-{
- struct region *reg;
-
- read_lock(&rh->hash_lock);
- reg = __rh_find(rh, region);
-
- spin_lock_irq(&rh->region_lock);
- atomic_inc(&reg->pending);
-
- if (reg->state == RH_CLEAN) {
- reg->state = RH_DIRTY;
- list_del_init(&reg->list); /* take off the clean list */
- spin_unlock_irq(&rh->region_lock);
-
- rh->log->type->mark_region(rh->log, reg->key);
- } else
- spin_unlock_irq(&rh->region_lock);
-
-
- read_unlock(&rh->hash_lock);
-}
-
-static void rh_inc_pending(struct region_hash *rh, struct bio_list *bios)
-{
- struct bio *bio;
-
- for (bio = bios->head; bio; bio = bio->bi_next)
- rh_inc(rh, bio_to_region(rh, bio));
-}
-
-static void rh_dec(struct region_hash *rh, region_t region)
+static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw)
{
unsigned long flags;
- struct region *reg;
int should_wake = 0;
+ struct bio_list *bl;
- read_lock(&rh->hash_lock);
- reg = __rh_lookup(rh, region);
- read_unlock(&rh->hash_lock);
-
- spin_lock_irqsave(&rh->region_lock, flags);
- if (atomic_dec_and_test(&reg->pending)) {
- /*
- * There is no pending I/O for this region.
- * We can move the region to corresponding list for next action.
- * At this point, the region is not yet connected to any list.
- *
- * If the state is RH_NOSYNC, the region should be kept off
- * from clean list.
- * The hash entry for RH_NOSYNC will remain in memory
- * until the region is recovered or the map is reloaded.
- */
-
- /* do nothing for RH_NOSYNC */
- if (reg->state == RH_RECOVERING) {
- list_add_tail(&reg->list, &rh->quiesced_regions);
- } else if (reg->state == RH_DIRTY) {
- reg->state = RH_CLEAN;
- list_add(&reg->list, &rh->clean_regions);
- }
- should_wake = 1;
- }
- spin_unlock_irqrestore(&rh->region_lock, flags);
+ bl = (rw == WRITE) ? &ms->writes : &ms->reads;
+ spin_lock_irqsave(&ms->lock, flags);
+ should_wake = !(bl->head);
+ bio_list_add(bl, bio);
+ spin_unlock_irqrestore(&ms->lock, flags);
if (should_wake)
- wake(rh->ms);
-}
-
-/*
- * Starts quiescing a region in preparation for recovery.
- */
-static int __rh_recovery_prepare(struct region_hash *rh)
-{
- int r;
- struct region *reg;
- region_t region;
-
- /*
- * Ask the dirty log what's next.
- */
- r = rh->log->type->get_resync_work(rh->log, &region);
- if (r <= 0)
- return r;
-
- /*
- * Get this region, and start it quiescing by setting the
- * recovering flag.
- */
- read_lock(&rh->hash_lock);
- reg = __rh_find(rh, region);
- read_unlock(&rh->hash_lock);
-
- spin_lock_irq(&rh->region_lock);
- reg->state = RH_RECOVERING;
-
- /* Already quiesced ? */
- if (atomic_read(&reg->pending))
- list_del_init(&reg->list);
- else
- list_move(&reg->list, &rh->quiesced_regions);
-
- spin_unlock_irq(&rh->region_lock);
-
- return 1;
-}
-
-static void rh_recovery_prepare(struct region_hash *rh)
-{
- /* Extra reference to avoid race with rh_stop_recovery */
- atomic_inc(&rh->recovery_in_flight);
-
- while (!down_trylock(&rh->recovery_count)) {
- atomic_inc(&rh->recovery_in_flight);
- if (__rh_recovery_prepare(rh) <= 0) {
- atomic_dec(&rh->recovery_in_flight);
- up(&rh->recovery_count);
- break;
- }
- }
-
- /* Drop the extra reference */
- if (atomic_dec_and_test(&rh->recovery_in_flight))
- wake_up_all(&_kmirrord_recovery_stopped);
-}
-
-/*
- * Returns any quiesced regions.
- */
-static struct region *rh_recovery_start(struct region_hash *rh)
-{
- struct region *reg = NULL;
-
- spin_lock_irq(&rh->region_lock);
- if (!list_empty(&rh->quiesced_regions)) {
- reg = list_entry(rh->quiesced_regions.next,
- struct region, list);
- list_del_init(&reg->list); /* remove from the quiesced list */
- }
- spin_unlock_irq(&rh->region_lock);
-
- return reg;
-}
-
-static void rh_recovery_end(struct region *reg, int success)
-{
- struct region_hash *rh = reg->rh;
-
- spin_lock_irq(&rh->region_lock);
- if (success)
- list_add(&reg->list, &reg->rh->recovered_regions);
- else {
- reg->state = RH_NOSYNC;
- list_add(&reg->list, &reg->rh->failed_recovered_regions);
- }
- spin_unlock_irq(&rh->region_lock);
-
- wake(rh->ms);
+ wakeup_mirrord(ms);
}
-static int rh_flush(struct region_hash *rh)
+static void dispatch_bios(void *context, struct bio_list *bio_list)
{
- return rh->log->type->flush(rh->log);
-}
-
-static void rh_delay(struct region_hash *rh, struct bio *bio)
-{
- struct region *reg;
-
- read_lock(&rh->hash_lock);
- reg = __rh_find(rh, bio_to_region(rh, bio));
- bio_list_add(&reg->delayed_bios, bio);
- read_unlock(&rh->hash_lock);
-}
-
-static void rh_stop_recovery(struct region_hash *rh)
-{
- int i;
-
- /* wait for any recovering regions */
- for (i = 0; i < MAX_RECOVERY; i++)
- down(&rh->recovery_count);
-}
-
-static void rh_start_recovery(struct region_hash *rh)
-{
- int i;
-
- for (i = 0; i < MAX_RECOVERY; i++)
- up(&rh->recovery_count);
+ struct mirror_set *ms = context;
+ struct bio *bio;
- wake(rh->ms);
+ while ((bio = bio_list_pop(bio_list)))
+ queue_bio(ms, bio, WRITE);
}
#define MIN_READ_RECORDS 20
@@ -776,8 +246,8 @@ out:
static void recovery_complete(int read_err, unsigned long write_err,
void *context)
{
- struct region *reg = (struct region *)context;
- struct mirror_set *ms = reg->rh->ms;
+ struct dm_region *reg = context;
+ struct mirror_set *ms = dm_rh_region_context(reg);
int m, bit = 0;
if (read_err) {
@@ -803,31 +273,33 @@ static void recovery_complete(int read_err, unsigned long write_err,
}
}
- rh_recovery_end(reg, !(read_err || write_err));
+ dm_rh_recovery_end(reg, !(read_err || write_err));
}
-static int recover(struct mirror_set *ms, struct region *reg)
+static int recover(struct mirror_set *ms, struct dm_region *reg)
{
int r;
- unsigned int i;
+ unsigned i;
struct dm_io_region from, to[DM_KCOPYD_MAX_REGIONS], *dest;
struct mirror *m;
unsigned long flags = 0;
+ region_t key = dm_rh_get_region_key(reg);
+ sector_t region_size = dm_rh_get_region_size(ms->rh);
/* fill in the source */
m = get_default_mirror(ms);
from.bdev = m->dev->bdev;
- from.sector = m->offset + region_to_sector(reg->rh, reg->key);
- if (reg->key == (ms->nr_regions - 1)) {
+ from.sector = m->offset + dm_rh_region_to_sector(ms->rh, key);
+ if (key == (ms->nr_regions - 1)) {
/*
* The final region may be smaller than
* region_size.
*/
- from.count = ms->ti->len & (reg->rh->region_size - 1);
+ from.count = ms->ti->len & (region_size - 1);
if (!from.count)
- from.count = reg->rh->region_size;
+ from.count = region_size;
} else
- from.count = reg->rh->region_size;
+ from.count = region_size;
/* fill in the destinations */
for (i = 0, dest = to; i < ms->nr_mirrors; i++) {
@@ -836,7 +308,7 @@ static int recover(struct mirror_set *ms, struct region *reg)
m = ms->mirror + i;
dest->bdev = m->dev->bdev;
- dest->sector = m->offset + region_to_sector(reg->rh, reg->key);
+ dest->sector = m->offset + dm_rh_region_to_sector(ms->rh, key);
dest->count = from.count;
dest++;
}
@@ -853,22 +325,22 @@ static int recover(struct mirror_set *ms, struct region *reg)
static void do_recovery(struct mirror_set *ms)
{
+ struct dm_region *reg;
+ struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
int r;
- struct region *reg;
- struct dm_dirty_log *log = ms->rh.log;
/*
* Start quiescing some regions.
*/
- rh_recovery_prepare(&ms->rh);
+ dm_rh_recovery_prepare(ms->rh);
/*
* Copy any already quiesced regions.
*/
- while ((reg = rh_recovery_start(&ms->rh))) {
+ while ((reg = dm_rh_recovery_start(ms->rh))) {
r = recover(ms, reg);
if (r)
- rh_recovery_end(reg, 0);
+ dm_rh_recovery_end(reg, 0);
}
/*
@@ -909,9 +381,10 @@ static int default_ok(struct mirror *m)
static int mirror_available(struct mirror_set *ms, struct bio *bio)
{
- region_t region = bio_to_region(&ms->rh, bio);
+ struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
+ region_t region = dm_rh_bio_to_region(ms->rh, bio);
- if (ms->rh.log->type->in_sync(ms->rh.log, region, 0))
+ if (log->type->in_sync(log, region, 0))
return choose_mirror(ms, bio->bi_sector) ? 1 : 0;
return 0;
@@ -985,7 +458,14 @@ static void read_async_bio(struct mirror *m, struct bio *bio)
map_region(&io, m, bio);
bio_set_m(bio, m);
- (void) dm_io(&io_req, 1, &io, NULL);
+ BUG_ON(dm_io(&io_req, 1, &io, NULL));
+}
+
+static inline int region_in_sync(struct mirror_set *ms, region_t region,
+ int may_block)
+{
+ int state = dm_rh_get_state(ms->rh, region, may_block);
+ return state == DM_RH_CLEAN || state == DM_RH_DIRTY;
}
static void do_reads(struct mirror_set *ms, struct bio_list *reads)
@@ -995,13 +475,13 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads)
struct mirror *m;
while ((bio = bio_list_pop(reads))) {
- region = bio_to_region(&ms->rh, bio);
+ region = dm_rh_bio_to_region(ms->rh, bio);
m = get_default_mirror(ms);
/*
* We can only read balance if the region is in sync.
*/
- if (likely(rh_in_sync(&ms->rh, region, 1)))
+ if (likely(region_in_sync(ms, region, 1)))
m = choose_mirror(ms, bio->bi_sector);
else if (m && atomic_read(&m->error_count))
m = NULL;
@@ -1024,57 +504,6 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads)
* NOSYNC: increment pending, just write to the default mirror
*---------------------------------------------------------------*/
-/* __bio_mark_nosync
- * @ms
- * @bio
- * @done
- * @error
- *
- * The bio was written on some mirror(s) but failed on other mirror(s).
- * We can successfully endio the bio but should avoid the region being
- * marked clean by setting the state RH_NOSYNC.
- *
- * This function is _not_ safe in interrupt context!
- */
-static void __bio_mark_nosync(struct mirror_set *ms,
- struct bio *bio, unsigned done, int error)
-{
- unsigned long flags;
- struct region_hash *rh = &ms->rh;
- struct dm_dirty_log *log = ms->rh.log;
- struct region *reg;
- region_t region = bio_to_region(rh, bio);
- int recovering = 0;
-
- /* We must inform the log that the sync count has changed. */
- log->type->set_region_sync(log, region, 0);
- ms->in_sync = 0;
-
- read_lock(&rh->hash_lock);
- reg = __rh_find(rh, region);
- read_unlock(&rh->hash_lock);
-
- /* region hash entry should exist because write was in-flight */
- BUG_ON(!reg);
- BUG_ON(!list_empty(&reg->list));
-
- spin_lock_irqsave(&rh->region_lock, flags);
- /*
- * Possible cases:
- * 1) RH_DIRTY
- * 2) RH_NOSYNC: was dirty, other preceeding writes failed
- * 3) RH_RECOVERING: flushing pending writes
- * Either case, the region should have not been connected to list.
- */
- recovering = (reg->state == RH_RECOVERING);
- reg->state = RH_NOSYNC;
- BUG_ON(!list_empty(&reg->list));
- spin_unlock_irqrestore(&rh->region_lock, flags);
-
- bio_endio(bio, error);
- if (recovering)
- complete_resync_work(reg, 0);
-}
static void write_callback(unsigned long error, void *context)
{
@@ -1119,7 +548,7 @@ static void write_callback(unsigned long error, void *context)
bio_list_add(&ms->failures, bio);
spin_unlock_irqrestore(&ms->lock, flags);
if (should_wake)
- wake(ms);
+ wakeup_mirrord(ms);
return;
}
out:
@@ -1149,7 +578,7 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
*/
bio_set_m(bio, get_default_mirror(ms));
- (void) dm_io(&io_req, ms->nr_mirrors, io, NULL);
+ BUG_ON(dm_io(&io_req, ms->nr_mirrors, io, NULL));
}
static void do_writes(struct mirror_set *ms, struct bio_list *writes)
@@ -1169,18 +598,19 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
bio_list_init(&recover);
while ((bio = bio_list_pop(writes))) {
- state = rh_state(&ms->rh, bio_to_region(&ms->rh, bio), 1);
+ state = dm_rh_get_state(ms->rh,
+ dm_rh_bio_to_region(ms->rh, bio), 1);
switch (state) {
- case RH_CLEAN:
- case RH_DIRTY:
+ case DM_RH_CLEAN:
+ case DM_RH_DIRTY:
this_list = &sync;
break;
- case RH_NOSYNC:
+ case DM_RH_NOSYNC:
this_list = &nosync;
break;
- case RH_RECOVERING:
+ case DM_RH_RECOVERING:
this_list = &recover;
break;
}
@@ -1193,9 +623,9 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
* be written to (writes to recover regions are going to
* be delayed).
*/
- rh_inc_pending(&ms->rh, &sync);
- rh_inc_pending(&ms->rh, &nosync);
- ms->log_failure = rh_flush(&ms->rh) ? 1 : 0;
+ dm_rh_inc_pending(ms->rh, &sync);
+ dm_rh_inc_pending(ms->rh, &nosync);
+ ms->log_failure = dm_rh_flush(ms->rh) ? 1 : 0;
/*
* Dispatch io.
@@ -1204,13 +634,13 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
spin_lock_irq(&ms->lock);
bio_list_merge(&ms->failures, &sync);
spin_unlock_irq(&ms->lock);
- wake(ms);
+ wakeup_mirrord(ms);
} else
while ((bio = bio_list_pop(&sync)))
do_write(ms, bio);
while ((bio = bio_list_pop(&recover)))
- rh_delay(&ms->rh, bio);
+ dm_rh_delay(ms->rh, bio);
while ((bio = bio_list_pop(&nosync))) {
map_bio(get_default_mirror(ms), bio);
@@ -1227,7 +657,8 @@ static void do_failures(struct mirror_set *ms, struct bio_list *failures)
if (!ms->log_failure) {
while ((bio = bio_list_pop(failures)))
- __bio_mark_nosync(ms, bio, bio->bi_size, 0);
+ ms->in_sync = 0;
+ dm_rh_mark_nosync(ms->rh, bio, bio->bi_size, 0);
return;
}
@@ -1280,8 +711,8 @@ static void trigger_event(struct work_struct *work)
*---------------------------------------------------------------*/
static void do_mirror(struct work_struct *work)
{
- struct mirror_set *ms =container_of(work, struct mirror_set,
- kmirrord_work);
+ struct mirror_set *ms = container_of(work, struct mirror_set,
+ kmirrord_work);
struct bio_list reads, writes, failures;
unsigned long flags;
@@ -1294,7 +725,7 @@ static void do_mirror(struct work_struct *work)
bio_list_init(&ms->failures);
spin_unlock_irqrestore(&ms->lock, flags);
- rh_update_states(&ms->rh);
+ dm_rh_update_states(ms->rh, errors_handled(ms));
do_recovery(ms);
do_reads(ms, &reads);
do_writes(ms, &writes);
@@ -1303,7 +734,6 @@ static void do_mirror(struct work_struct *work)
dm_table_unplug_all(ms->ti->table);
}
-
/*-----------------------------------------------------------------
* Target functions
*---------------------------------------------------------------*/
@@ -1315,9 +745,6 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
size_t len;
struct mirror_set *ms = NULL;
- if (array_too_big(sizeof(*ms), sizeof(ms->mirror[0]), nr_mirrors))
- return NULL;
-
len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors);
ms = kzalloc(len, GFP_KERNEL);
@@ -1353,7 +780,11 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
return NULL;
}
- if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {
+ ms->rh = dm_region_hash_create(ms, dispatch_bios, wakeup_mirrord,
+ wakeup_all_recovery_waiters,
+ ms->ti->begin, MAX_RECOVERY,
+ dl, region_size, ms->nr_regions);
+ if (IS_ERR(ms->rh)) {
ti->error = "Error creating dirty region hash";
dm_io_client_destroy(ms->io_client);
mempool_destroy(ms->read_record_pool);
@@ -1371,7 +802,7 @@ static void free_context(struct mirror_set *ms, struct dm_target *ti,
dm_put_device(ti, ms->mirror[m].dev);
dm_io_client_destroy(ms->io_client);
- rh_exit(&ms->rh);
+ dm_region_hash_destroy(ms->rh);
mempool_destroy(ms->read_record_pool);
kfree(ms);
}
@@ -1411,10 +842,10 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
* Create dirty log: log_type #log_params <log_params>
*/
static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
- unsigned int argc, char **argv,
- unsigned int *args_used)
+ unsigned argc, char **argv,
+ unsigned *args_used)
{
- unsigned int param_count;
+ unsigned param_count;
struct dm_dirty_log *dl;
if (argc < 2) {
@@ -1545,7 +976,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
ti->private = ms;
- ti->split_io = ms->rh.region_size;
+ ti->split_io = dm_rh_get_region_size(ms->rh);
ms->kmirrord_wq = create_singlethread_workqueue("kmirrord");
if (!ms->kmirrord_wq) {
@@ -1580,11 +1011,11 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto err_destroy_wq;
}
- r = dm_kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
+ r = dm_kcopyd_client_create(DM_KCOPYD_PAGES, &ms->kcopyd_client);
if (r)
goto err_destroy_wq;
- wake(ms);
+ wakeup_mirrord(ms);
return 0;
err_destroy_wq:
@@ -1605,22 +1036,6 @@ static void mirror_dtr(struct dm_target *ti)
free_context(ms, ti, ms->nr_mirrors);
}
-static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw)
-{
- unsigned long flags;
- int should_wake = 0;
- struct bio_list *bl;
-
- bl = (rw == WRITE) ? &ms->writes : &ms->reads;
- spin_lock_irqsave(&ms->lock, flags);
- should_wake = !(bl->head);
- bio_list_add(bl, bio);
- spin_unlock_irqrestore(&ms->lock, flags);
-
- if (should_wake)
- wake(ms);
-}
-
/*
* Mirror mapping function
*/
@@ -1631,16 +1046,16 @@ static int mirror_map(struct dm_target *ti, struct bio *bio,
struct mirror *m;
struct mirror_set *ms = ti->private;
struct dm_raid1_read_record *read_record = NULL;
+ struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
if (rw == WRITE) {
/* Save region for mirror_end_io() handler */
- map_context->ll = bio_to_region(&ms->rh, bio);
+ map_context->ll = dm_rh_bio_to_region(ms->rh, bio);
queue_bio(ms, bio, rw);
return DM_MAPIO_SUBMITTED;
}
- r = ms->rh.log->type->in_sync(ms->rh.log,
- bio_to_region(&ms->rh, bio), 0);
+ r = log->type->in_sync(log, dm_rh_bio_to_region(ms->rh, bio), 0);
if (r < 0 && r != -EWOULDBLOCK)
return r;
@@ -1688,7 +1103,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio,
* We need to dec pending if this was a write.
*/
if (rw == WRITE) {
- rh_dec(&ms->rh, map_context->ll);
+ dm_rh_dec(ms->rh, map_context->ll);
return error;
}
@@ -1744,7 +1159,7 @@ out:
static void mirror_presuspend(struct dm_target *ti)
{
struct mirror_set *ms = (struct mirror_set *) ti->private;
- struct dm_dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
atomic_set(&ms->suspend, 1);
@@ -1752,10 +1167,10 @@ static void mirror_presuspend(struct dm_target *ti)
* We must finish up all the work that we've
* generated (i.e. recovery work).
*/
- rh_stop_recovery(&ms->rh);
+ dm_rh_stop_recovery(ms->rh);
wait_event(_kmirrord_recovery_stopped,
- !atomic_read(&ms->rh.recovery_in_flight));
+ !dm_rh_recovery_in_flight(ms->rh));
if (log->type->presuspend && log->type->presuspend(log))
/* FIXME: need better error handling */
@@ -1773,7 +1188,7 @@ static void mirror_presuspend(struct dm_target *ti)
static void mirror_postsuspend(struct dm_target *ti)
{
struct mirror_set *ms = ti->private;
- struct dm_dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
if (log->type->postsuspend && log->type->postsuspend(log))
/* FIXME: need better error handling */
@@ -1783,13 +1198,13 @@ static void mirror_postsuspend(struct dm_target *ti)
static void mirror_resume(struct dm_target *ti)
{
struct mirror_set *ms = ti->private;
- struct dm_dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
atomic_set(&ms->suspend, 0);
if (log->type->resume && log->type->resume(log))
/* FIXME: need better error handling */
DMWARN("log resume failed");
- rh_start_recovery(&ms->rh);
+ dm_rh_start_recovery(ms->rh);
}
/*
@@ -1821,7 +1236,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
{
unsigned int m, sz = 0;
struct mirror_set *ms = (struct mirror_set *) ti->private;
- struct dm_dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
char buffer[ms->nr_mirrors + 1];
switch (type) {
@@ -1834,15 +1249,15 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
buffer[m] = '\0';
DMEMIT("%llu/%llu 1 %s ",
- (unsigned long long)log->type->get_sync_count(ms->rh.log),
+ (unsigned long long)log->type->get_sync_count(log),
(unsigned long long)ms->nr_regions, buffer);
- sz += log->type->status(ms->rh.log, type, result+sz, maxlen-sz);
+ sz += log->type->status(log, type, result+sz, maxlen-sz);
break;
case STATUSTYPE_TABLE:
- sz = log->type->status(ms->rh.log, type, result, maxlen);
+ sz = log->type->status(log, type, result, maxlen);
DMEMIT("%d", ms->nr_mirrors);
for (m = 0; m < ms->nr_mirrors; m++)
diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c
new file mode 100644
index 00000000000..59f8d9df9e1
--- /dev/null
+++ b/drivers/md/dm-region-hash.c
@@ -0,0 +1,704 @@
+/*
+ * Copyright (C) 2003 Sistina Software Limited.
+ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/dm-dirty-log.h>
+#include <linux/dm-region-hash.h>
+
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include "dm.h"
+#include "dm-bio-list.h"
+
+#define DM_MSG_PREFIX "region hash"
+
+/*-----------------------------------------------------------------
+ * Region hash
+ *
+ * The mirror splits itself up into discrete regions. Each
+ * region can be in one of three states: clean, dirty,
+ * nosync. There is no need to put clean regions in the hash.
+ *
+ * In addition to being present in the hash table a region _may_
+ * be present on one of three lists.
+ *
+ * clean_regions: Regions on this list have no io pending to
+ * them, they are in sync, we are no longer interested in them,
+ * they are dull. dm_rh_update_states() will remove them from the
+ * hash table.
+ *
+ * quiesced_regions: These regions have been spun down, ready
+ * for recovery. rh_recovery_start() will remove regions from
+ * this list and hand them to kmirrord, which will schedule the
+ * recovery io with kcopyd.
+ *
+ * recovered_regions: Regions that kcopyd has successfully
+ * recovered. dm_rh_update_states() will now schedule any delayed
+ * io, up the recovery_count, and remove the region from the
+ * hash.
+ *
+ * There are 2 locks:
+ * A rw spin lock 'hash_lock' protects just the hash table,
+ * this is never held in write mode from interrupt context,
+ * which I believe means that we only have to disable irqs when
+ * doing a write lock.
+ *
+ * An ordinary spin lock 'region_lock' that protects the three
+ * lists in the region_hash, with the 'state', 'list' and
+ * 'delayed_bios' fields of the regions. This is used from irq
+ * context, so all other uses will have to suspend local irqs.
+ *---------------------------------------------------------------*/
+struct dm_region_hash {
+ uint32_t region_size;
+ unsigned region_shift;
+
+ /* holds persistent region state */
+ struct dm_dirty_log *log;
+
+ /* hash table */
+ rwlock_t hash_lock;
+ mempool_t *region_pool;
+ unsigned mask;
+ unsigned nr_buckets;
+ unsigned prime;
+ unsigned shift;
+ struct list_head *buckets;
+
+ unsigned max_recovery; /* Max # of regions to recover in parallel */
+
+ spinlock_t region_lock;
+ atomic_t recovery_in_flight;
+ struct semaphore recovery_count;
+ struct list_head clean_regions;
+ struct list_head quiesced_regions;
+ struct list_head recovered_regions;
+ struct list_head failed_recovered_regions;
+
+ void *context;
+ sector_t target_begin;
+
+ /* Callback function to schedule bios writes */
+ void (*dispatch_bios)(void *context, struct bio_list *bios);
+
+ /* Callback function to wakeup callers worker thread. */
+ void (*wakeup_workers)(void *context);
+
+ /* Callback function to wakeup callers recovery waiters. */
+ void (*wakeup_all_recovery_waiters)(void *context);
+};
+
+struct dm_region {
+ struct dm_region_hash *rh; /* FIXME: can we get rid of this ? */
+ region_t key;
+ int state;
+
+ struct list_head hash_list;
+ struct list_head list;
+
+ atomic_t pending;
+ struct bio_list delayed_bios;
+};
+
+/*
+ * Conversion fns
+ */
+static region_t dm_rh_sector_to_region(struct dm_region_hash *rh, sector_t sector)
+{
+ return sector >> rh->region_shift;
+}
+
+sector_t dm_rh_region_to_sector(struct dm_region_hash *rh, region_t region)
+{
+ return region << rh->region_shift;
+}
+EXPORT_SYMBOL_GPL(dm_rh_region_to_sector);
+
+region_t dm_rh_bio_to_region(struct dm_region_hash *rh, struct bio *bio)
+{
+ return dm_rh_sector_to_region(rh, bio->bi_sector - rh->target_begin);
+}
+EXPORT_SYMBOL_GPL(dm_rh_bio_to_region);
+
+void *dm_rh_region_context(struct dm_region *reg)
+{
+ return reg->rh->context;
+}
+EXPORT_SYMBOL_GPL(dm_rh_region_context);
+
+region_t dm_rh_get_region_key(struct dm_region *reg)
+{
+ return reg->key;
+}
+EXPORT_SYMBOL_GPL(dm_rh_get_region_key);
+
+sector_t dm_rh_get_region_size(struct dm_region_hash *rh)
+{
+ return rh->region_size;
+}
+EXPORT_SYMBOL_GPL(dm_rh_get_region_size);
+
+/*
+ * FIXME: shall we pass in a structure instead of all these args to
+ * dm_region_hash_create()????
+ */
+#define RH_HASH_MULT 2654435387U
+#define RH_HASH_SHIFT 12
+
+#define MIN_REGIONS 64
+struct dm_region_hash *dm_region_hash_create(
+ void *context, void (*dispatch_bios)(void *context,
+ struct bio_list *bios),
+ void (*wakeup_workers)(void *context),
+ void (*wakeup_all_recovery_waiters)(void *context),
+ sector_t target_begin, unsigned max_recovery,
+ struct dm_dirty_log *log, uint32_t region_size,
+ region_t nr_regions)
+{
+ struct dm_region_hash *rh;
+ unsigned nr_buckets, max_buckets;
+ size_t i;
+
+ /*
+ * Calculate a suitable number of buckets for our hash
+ * table.
+ */
+ max_buckets = nr_regions >> 6;
+ for (nr_buckets = 128u; nr_buckets < max_buckets; nr_buckets <<= 1)
+ ;
+ nr_buckets >>= 1;
+
+ rh = kmalloc(sizeof(*rh), GFP_KERNEL);
+ if (!rh) {
+ DMERR("unable to allocate region hash memory");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ rh->context = context;
+ rh->dispatch_bios = dispatch_bios;
+ rh->wakeup_workers = wakeup_workers;
+ rh->wakeup_all_recovery_waiters = wakeup_all_recovery_waiters;
+ rh->target_begin = target_begin;
+ rh->max_recovery = max_recovery;
+ rh->log = log;
+ rh->region_size = region_size;
+ rh->region_shift = ffs(region_size) - 1;
+ rwlock_init(&rh->hash_lock);
+ rh->mask = nr_buckets - 1;
+ rh->nr_buckets = nr_buckets;
+
+ rh->shift = RH_HASH_SHIFT;
+ rh->prime = RH_HASH_MULT;
+
+ rh->buckets = vmalloc(nr_buckets * sizeof(*rh->buckets));
+ if (!rh->buckets) {
+ DMERR("unable to allocate region hash bucket memory");
+ kfree(rh);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0; i < nr_buckets; i++)
+ INIT_LIST_HEAD(rh->buckets + i);
+
+ spin_lock_init(&rh->region_lock);
+ sema_init(&rh->recovery_count, 0);
+ atomic_set(&rh->recovery_in_flight, 0);
+ INIT_LIST_HEAD(&rh->clean_regions);
+ INIT_LIST_HEAD(&rh->quiesced_regions);
+ INIT_LIST_HEAD(&rh->recovered_regions);
+ INIT_LIST_HEAD(&rh->failed_recovered_regions);
+
+ rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS,
+ sizeof(struct dm_region));
+ if (!rh->region_pool) {
+ vfree(rh->buckets);
+ kfree(rh);
+ rh = ERR_PTR(-ENOMEM);
+ }
+
+ return rh;
+}
+EXPORT_SYMBOL_GPL(dm_region_hash_create);
+
+void dm_region_hash_destroy(struct dm_region_hash *rh)
+{
+ unsigned h;
+ struct dm_region *reg, *nreg;
+
+ BUG_ON(!list_empty(&rh->quiesced_regions));
+ for (h = 0; h < rh->nr_buckets; h++) {
+ list_for_each_entry_safe(reg, nreg, rh->buckets + h,
+ hash_list) {
+ BUG_ON(atomic_read(&reg->pending));
+ mempool_free(reg, rh->region_pool);
+ }
+ }
+
+ if (rh->log)
+ dm_dirty_log_destroy(rh->log);
+
+ if (rh->region_pool)
+ mempool_destroy(rh->region_pool);
+
+ vfree(rh->buckets);
+ kfree(rh);
+}
+EXPORT_SYMBOL_GPL(dm_region_hash_destroy);
+
+struct dm_dirty_log *dm_rh_dirty_log(struct dm_region_hash *rh)
+{
+ return rh->log;
+}
+EXPORT_SYMBOL_GPL(dm_rh_dirty_log);
+
+static unsigned rh_hash(struct dm_region_hash *rh, region_t region)
+{
+ return (unsigned) ((region * rh->prime) >> rh->shift) & rh->mask;
+}
+
+static struct dm_region *__rh_lookup(struct dm_region_hash *rh, region_t region)
+{
+ struct dm_region *reg;
+ struct list_head *bucket = rh->buckets + rh_hash(rh, region);
+
+ list_for_each_entry(reg, bucket, hash_list)
+ if (reg->key == region)
+ return reg;
+
+ return NULL;
+}
+
+static void __rh_insert(struct dm_region_hash *rh, struct dm_region *reg)
+{
+ list_add(&reg->hash_list, rh->buckets + rh_hash(rh, reg->key));
+}
+
+static struct dm_region *__rh_alloc(struct dm_region_hash *rh, region_t region)
+{
+ struct dm_region *reg, *nreg;
+
+ nreg = mempool_alloc(rh->region_pool, GFP_ATOMIC);
+ if (unlikely(!nreg))
+ nreg = kmalloc(sizeof(*nreg), GFP_NOIO);
+
+ nreg->state = rh->log->type->in_sync(rh->log, region, 1) ?
+ DM_RH_CLEAN : DM_RH_NOSYNC;
+ nreg->rh = rh;
+ nreg->key = region;
+ INIT_LIST_HEAD(&nreg->list);
+ atomic_set(&nreg->pending, 0);
+ bio_list_init(&nreg->delayed_bios);
+
+ write_lock_irq(&rh->hash_lock);
+ reg = __rh_lookup(rh, region);
+ if (reg)
+ /* We lost the race. */
+ mempool_free(nreg, rh->region_pool);
+ else {
+ __rh_insert(rh, nreg);
+ if (nreg->state == DM_RH_CLEAN) {
+ spin_lock(&rh->region_lock);
+ list_add(&nreg->list, &rh->clean_regions);
+ spin_unlock(&rh->region_lock);
+ }
+
+ reg = nreg;
+ }
+ write_unlock_irq(&rh->hash_lock);
+
+ return reg;
+}
+
+static struct dm_region *__rh_find(struct dm_region_hash *rh, region_t region)
+{
+ struct dm_region *reg;
+
+ reg = __rh_lookup(rh, region);
+ if (!reg) {
+ read_unlock(&rh->hash_lock);
+ reg = __rh_alloc(rh, region);
+ read_lock(&rh->hash_lock);
+ }
+
+ return reg;
+}
+
+int dm_rh_get_state(struct dm_region_hash *rh, region_t region, int may_block)
+{
+ int r;
+ struct dm_region *reg;
+
+ read_lock(&rh->hash_lock);
+ reg = __rh_lookup(rh, region);
+ read_unlock(&rh->hash_lock);
+
+ if (reg)
+ return reg->state;
+
+ /*
+ * The region wasn't in the hash, so we fall back to the
+ * dirty log.
+ */
+ r = rh->log->type->in_sync(rh->log, region, may_block);
+
+ /*
+ * Any error from the dirty log (eg. -EWOULDBLOCK) gets
+ * taken as a DM_RH_NOSYNC
+ */
+ return r == 1 ? DM_RH_CLEAN : DM_RH_NOSYNC;
+}
+EXPORT_SYMBOL_GPL(dm_rh_get_state);
+
+static void complete_resync_work(struct dm_region *reg, int success)
+{
+ struct dm_region_hash *rh = reg->rh;
+
+ rh->log->type->set_region_sync(rh->log, reg->key, success);
+
+ /*
+ * Dispatch the bios before we call 'wake_up_all'.
+ * This is important because if we are suspending,
+ * we want to know that recovery is complete and
+ * the work queue is flushed. If we wake_up_all
+ * before we dispatch_bios (queue bios and call wake()),
+ * then we risk suspending before the work queue
+ * has been properly flushed.
+ */
+ rh->dispatch_bios(rh->context, &reg->delayed_bios);
+ if (atomic_dec_and_test(&rh->recovery_in_flight))
+ rh->wakeup_all_recovery_waiters(rh->context);
+ up(&rh->recovery_count);
+}
+
+/* dm_rh_mark_nosync
+ * @ms
+ * @bio
+ * @done
+ * @error
+ *
+ * The bio was written on some mirror(s) but failed on other mirror(s).
+ * We can successfully endio the bio but should avoid the region being
+ * marked clean by setting the state DM_RH_NOSYNC.
+ *
+ * This function is _not_ safe in interrupt context!
+ */
+void dm_rh_mark_nosync(struct dm_region_hash *rh,
+ struct bio *bio, unsigned done, int error)
+{
+ unsigned long flags;
+ struct dm_dirty_log *log = rh->log;
+ struct dm_region *reg;
+ region_t region = dm_rh_bio_to_region(rh, bio);
+ int recovering = 0;
+
+ /* We must inform the log that the sync count has changed. */
+ log->type->set_region_sync(log, region, 0);
+
+ read_lock(&rh->hash_lock);
+ reg = __rh_find(rh, region);
+ read_unlock(&rh->hash_lock);
+
+ /* region hash entry should exist because write was in-flight */
+ BUG_ON(!reg);
+ BUG_ON(!list_empty(&reg->list));
+
+ spin_lock_irqsave(&rh->region_lock, flags);
+ /*
+ * Possible cases:
+ * 1) DM_RH_DIRTY
+ * 2) DM_RH_NOSYNC: was dirty, other preceeding writes failed
+ * 3) DM_RH_RECOVERING: flushing pending writes
+ * Either case, the region should have not been connected to list.
+ */
+ recovering = (reg->state == DM_RH_RECOVERING);
+ reg->state = DM_RH_NOSYNC;
+ BUG_ON(!list_empty(&reg->list));
+ spin_unlock_irqrestore(&rh->region_lock, flags);
+
+ bio_endio(bio, error);
+ if (recovering)
+ complete_resync_work(reg, 0);
+}
+EXPORT_SYMBOL_GPL(dm_rh_mark_nosync);
+
+void dm_rh_update_states(struct dm_region_hash *rh, int errors_handled)
+{
+ struct dm_region *reg, *next;
+
+ LIST_HEAD(clean);
+ LIST_HEAD(recovered);
+ LIST_HEAD(failed_recovered);
+
+ /*
+ * Quickly grab the lists.
+ */
+ write_lock_irq(&rh->hash_lock);
+ spin_lock(&rh->region_lock);
+ if (!list_empty(&rh->clean_regions)) {
+ list_splice_init(&rh->clean_regions, &clean);
+
+ list_for_each_entry(reg, &clean, list)
+ list_del(&reg->hash_list);
+ }
+
+ if (!list_empty(&rh->recovered_regions)) {
+ list_splice_init(&rh->recovered_regions, &recovered);
+
+ list_for_each_entry(reg, &recovered, list)
+ list_del(&reg->hash_list);
+ }
+
+ if (!list_empty(&rh->failed_recovered_regions)) {
+ list_splice_init(&rh->failed_recovered_regions,
+ &failed_recovered);
+
+ list_for_each_entry(reg, &failed_recovered, list)
+ list_del(&reg->hash_list);
+ }
+
+ spin_unlock(&rh->region_lock);
+ write_unlock_irq(&rh->hash_lock);
+
+ /*
+ * All the regions on the recovered and clean lists have
+ * now been pulled out of the system, so no need to do
+ * any more locking.
+ */
+ list_for_each_entry_safe(reg, next, &recovered, list) {
+ rh->log->type->clear_region(rh->log, reg->key);
+ complete_resync_work(reg, 1);
+ mempool_free(reg, rh->region_pool);
+ }
+
+ list_for_each_entry_safe(reg, next, &failed_recovered, list) {
+ complete_resync_work(reg, errors_handled ? 0 : 1);
+ mempool_free(reg, rh->region_pool);
+ }
+
+ list_for_each_entry_safe(reg, next, &clean, list) {
+ rh->log->type->clear_region(rh->log, reg->key);
+ mempool_free(reg, rh->region_pool);
+ }
+
+ rh->log->type->flush(rh->log);
+}
+EXPORT_SYMBOL_GPL(dm_rh_update_states);
+
+static void rh_inc(struct dm_region_hash *rh, region_t region)
+{
+ struct dm_region *reg;
+
+ read_lock(&rh->hash_lock);
+ reg = __rh_find(rh, region);
+
+ spin_lock_irq(&rh->region_lock);
+ atomic_inc(&reg->pending);
+
+ if (reg->state == DM_RH_CLEAN) {
+ reg->state = DM_RH_DIRTY;
+ list_del_init(&reg->list); /* take off the clean list */
+ spin_unlock_irq(&rh->region_lock);
+
+ rh->log->type->mark_region(rh->log, reg->key);
+ } else
+ spin_unlock_irq(&rh->region_lock);
+
+
+ read_unlock(&rh->hash_lock);
+}
+
+void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios)
+{
+ struct bio *bio;
+
+ for (bio = bios->head; bio; bio = bio->bi_next)
+ rh_inc(rh, dm_rh_bio_to_region(rh, bio));
+}
+EXPORT_SYMBOL_GPL(dm_rh_inc_pending);
+
+void dm_rh_dec(struct dm_region_hash *rh, region_t region)
+{
+ unsigned long flags;
+ struct dm_region *reg;
+ int should_wake = 0;
+
+ read_lock(&rh->hash_lock);
+ reg = __rh_lookup(rh, region);
+ read_unlock(&rh->hash_lock);
+
+ spin_lock_irqsave(&rh->region_lock, flags);
+ if (atomic_dec_and_test(&reg->pending)) {
+ /*
+ * There is no pending I/O for this region.
+ * We can move the region to corresponding list for next action.
+ * At this point, the region is not yet connected to any list.
+ *
+ * If the state is DM_RH_NOSYNC, the region should be kept off
+ * from clean list.
+ * The hash entry for DM_RH_NOSYNC will remain in memory
+ * until the region is recovered or the map is reloaded.
+ */
+
+ /* do nothing for DM_RH_NOSYNC */
+ if (reg->state == DM_RH_RECOVERING) {
+ list_add_tail(&reg->list, &rh->quiesced_regions);
+ } else if (reg->state == DM_RH_DIRTY) {
+ reg->state = DM_RH_CLEAN;
+ list_add(&reg->list, &rh->clean_regions);
+ }
+ should_wake = 1;
+ }
+ spin_unlock_irqrestore(&rh->region_lock, flags);
+
+ if (should_wake)
+ rh->wakeup_workers(rh->context);
+}
+EXPORT_SYMBOL_GPL(dm_rh_dec);
+
+/*
+ * Starts quiescing a region in preparation for recovery.
+ */
+static int __rh_recovery_prepare(struct dm_region_hash *rh)
+{
+ int r;
+ region_t region;
+ struct dm_region *reg;
+
+ /*
+ * Ask the dirty log what's next.
+ */
+ r = rh->log->type->get_resync_work(rh->log, &region);
+ if (r <= 0)
+ return r;
+
+ /*
+ * Get this region, and start it quiescing by setting the
+ * recovering flag.
+ */
+ read_lock(&rh->hash_lock);
+ reg = __rh_find(rh, region);
+ read_unlock(&rh->hash_lock);
+
+ spin_lock_irq(&rh->region_lock);
+ reg->state = DM_RH_RECOVERING;
+
+ /* Already quiesced ? */
+ if (atomic_read(&reg->pending))
+ list_del_init(&reg->list);
+ else
+ list_move(&reg->list, &rh->quiesced_regions);
+
+ spin_unlock_irq(&rh->region_lock);
+
+ return 1;
+}
+
+void dm_rh_recovery_prepare(struct dm_region_hash *rh)
+{
+ /* Extra reference to avoid race with dm_rh_stop_recovery */
+ atomic_inc(&rh->recovery_in_flight);
+
+ while (!down_trylock(&rh->recovery_count)) {
+ atomic_inc(&rh->recovery_in_flight);
+ if (__rh_recovery_prepare(rh) <= 0) {
+ atomic_dec(&rh->recovery_in_flight);
+ up(&rh->recovery_count);
+ break;
+ }
+ }
+
+ /* Drop the extra reference */
+ if (atomic_dec_and_test(&rh->recovery_in_flight))
+ rh->wakeup_all_recovery_waiters(rh->context);
+}
+EXPORT_SYMBOL_GPL(dm_rh_recovery_prepare);
+
+/*
+ * Returns any quiesced regions.
+ */
+struct dm_region *dm_rh_recovery_start(struct dm_region_hash *rh)
+{
+ struct dm_region *reg = NULL;
+
+ spin_lock_irq(&rh->region_lock);
+ if (!list_empty(&rh->quiesced_regions)) {
+ reg = list_entry(rh->quiesced_regions.next,
+ struct dm_region, list);
+ list_del_init(&reg->list); /* remove from the quiesced list */
+ }
+ spin_unlock_irq(&rh->region_lock);
+
+ return reg;
+}
+EXPORT_SYMBOL_GPL(dm_rh_recovery_start);
+
+void dm_rh_recovery_end(struct dm_region *reg, int success)
+{
+ struct dm_region_hash *rh = reg->rh;
+
+ spin_lock_irq(&rh->region_lock);
+ if (success)
+ list_add(&reg->list, &reg->rh->recovered_regions);
+ else {
+ reg->state = DM_RH_NOSYNC;
+ list_add(&reg->list, &reg->rh->failed_recovered_regions);
+ }
+ spin_unlock_irq(&rh->region_lock);
+
+ rh->wakeup_workers(rh->context);
+}
+EXPORT_SYMBOL_GPL(dm_rh_recovery_end);
+
+/* Return recovery in flight count. */
+int dm_rh_recovery_in_flight(struct dm_region_hash *rh)
+{
+ return atomic_read(&rh->recovery_in_flight);
+}
+EXPORT_SYMBOL_GPL(dm_rh_recovery_in_flight);
+
+int dm_rh_flush(struct dm_region_hash *rh)
+{
+ return rh->log->type->flush(rh->log);
+}
+EXPORT_SYMBOL_GPL(dm_rh_flush);
+
+void dm_rh_delay(struct dm_region_hash *rh, struct bio *bio)
+{
+ struct dm_region *reg;
+
+ read_lock(&rh->hash_lock);
+ reg = __rh_find(rh, dm_rh_bio_to_region(rh, bio));
+ bio_list_add(&reg->delayed_bios, bio);
+ read_unlock(&rh->hash_lock);
+}
+EXPORT_SYMBOL_GPL(dm_rh_delay);
+
+void dm_rh_stop_recovery(struct dm_region_hash *rh)
+{
+ int i;
+
+ /* wait for any recovering regions */
+ for (i = 0; i < rh->max_recovery; i++)
+ down(&rh->recovery_count);
+}
+EXPORT_SYMBOL_GPL(dm_rh_stop_recovery);
+
+void dm_rh_start_recovery(struct dm_region_hash *rh)
+{
+ int i;
+
+ for (i = 0; i < rh->max_recovery; i++)
+ up(&rh->recovery_count);
+
+ rh->wakeup_workers(rh->context);
+}
+EXPORT_SYMBOL_GPL(dm_rh_start_recovery);
+
+MODULE_DESCRIPTION(DM_NAME " region hash");
+MODULE_AUTHOR("Joe Thornber/Heinz Mauelshagen <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c
index 391dfa2ad43..cdfbf65b28c 100644
--- a/drivers/md/dm-round-robin.c
+++ b/drivers/md/dm-round-robin.c
@@ -9,7 +9,8 @@
* Round-robin path selector.
*/
-#include "dm.h"
+#include <linux/device-mapper.h>
+
#include "dm-path-selector.h"
#include <linux/slab.h>
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 6e5528aecc9..b2d9d1ac28a 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -600,7 +600,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
s->valid = 1;
s->active = 0;
- s->last_percent = 0;
init_rwsem(&s->lock);
spin_lock_init(&s->pe_lock);
s->ti = ti;
@@ -824,8 +823,10 @@ static struct bio *put_pending_exception(struct dm_snap_pending_exception *pe)
* the bios for the original write to the origin.
*/
if (primary_pe &&
- atomic_dec_and_test(&primary_pe->ref_count))
+ atomic_dec_and_test(&primary_pe->ref_count)) {
origin_bios = bio_list_get(&primary_pe->origin_bios);
+ free_pending_exception(primary_pe);
+ }
/*
* Free the pe if it's not linked to an origin write or if
@@ -834,12 +835,6 @@ static struct bio *put_pending_exception(struct dm_snap_pending_exception *pe)
if (!primary_pe || primary_pe != pe)
free_pending_exception(pe);
- /*
- * Free the primary pe if nothing references it.
- */
- if (primary_pe && !atomic_read(&primary_pe->ref_count))
- free_pending_exception(primary_pe);
-
return origin_bios;
}
diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h
index 292c15609ae..f07315fe236 100644
--- a/drivers/md/dm-snap.h
+++ b/drivers/md/dm-snap.h
@@ -9,7 +9,7 @@
#ifndef DM_SNAPSHOT_H
#define DM_SNAPSHOT_H
-#include "dm.h"
+#include <linux/device-mapper.h>
#include "dm-bio-list.h"
#include <linux/blkdev.h>
#include <linux/workqueue.h>
@@ -158,9 +158,6 @@ struct dm_snapshot {
/* Used for display of table */
char type;
- /* The last percentage we notified */
- int last_percent;
-
mempool_t *pending_pool;
struct exception_table pending;
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index b745d8ac625..a2d068dbe9e 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -4,7 +4,7 @@
* This file is released under the GPL.
*/
-#include "dm.h"
+#include <linux/device-mapper.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -60,8 +60,8 @@ static inline struct stripe_c *alloc_context(unsigned int stripes)
{
size_t len;
- if (array_too_big(sizeof(struct stripe_c), sizeof(struct stripe),
- stripes))
+ if (dm_array_too_big(sizeof(struct stripe_c), sizeof(struct stripe),
+ stripes))
return NULL;
len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes);
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index a740a6950f5..a63161aec48 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -43,7 +43,7 @@ struct dm_table {
* device. This should be a combination of FMODE_READ
* and FMODE_WRITE.
*/
- int mode;
+ fmode_t mode;
/* a list of devices used by this table */
struct list_head devices;
@@ -217,7 +217,7 @@ static int alloc_targets(struct dm_table *t, unsigned int num)
return 0;
}
-int dm_table_create(struct dm_table **result, int mode,
+int dm_table_create(struct dm_table **result, fmode_t mode,
unsigned num_targets, struct mapped_device *md)
{
struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
@@ -313,19 +313,6 @@ static inline int check_space(struct dm_table *t)
}
/*
- * Convert a device path to a dev_t.
- */
-static int lookup_device(const char *path, dev_t *dev)
-{
- struct block_device *bdev = lookup_bdev(path);
- if (IS_ERR(bdev))
- return PTR_ERR(bdev);
- *dev = bdev->bd_dev;
- bdput(bdev);
- return 0;
-}
-
-/*
* See if we've already got a device in the list.
*/
static struct dm_dev_internal *find_device(struct list_head *l, dev_t dev)
@@ -357,7 +344,7 @@ static int open_dev(struct dm_dev_internal *d, dev_t dev,
return PTR_ERR(bdev);
r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md));
if (r)
- blkdev_put(bdev);
+ blkdev_put(bdev, d->dm_dev.mode);
else
d->dm_dev.bdev = bdev;
return r;
@@ -372,7 +359,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
return;
bd_release_from_disk(d->dm_dev.bdev, dm_disk(md));
- blkdev_put(d->dm_dev.bdev);
+ blkdev_put(d->dm_dev.bdev, d->dm_dev.mode);
d->dm_dev.bdev = NULL;
}
@@ -395,7 +382,7 @@ static int check_device_area(struct dm_dev_internal *dd, sector_t start,
* careful to leave things as they were if we fail to reopen the
* device.
*/
-static int upgrade_mode(struct dm_dev_internal *dd, int new_mode,
+static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
struct mapped_device *md)
{
int r;
@@ -421,7 +408,7 @@ static int upgrade_mode(struct dm_dev_internal *dd, int new_mode,
*/
static int __table_get_device(struct dm_table *t, struct dm_target *ti,
const char *path, sector_t start, sector_t len,
- int mode, struct dm_dev **result)
+ fmode_t mode, struct dm_dev **result)
{
int r;
dev_t uninitialized_var(dev);
@@ -437,8 +424,12 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
return -EOVERFLOW;
} else {
/* convert the path to a device */
- if ((r = lookup_device(path, &dev)))
- return r;
+ struct block_device *bdev = lookup_bdev(path);
+
+ if (IS_ERR(bdev))
+ return PTR_ERR(bdev);
+ dev = bdev->bd_dev;
+ bdput(bdev);
}
dd = find_device(&t->devices, dev);
@@ -537,7 +528,7 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
EXPORT_SYMBOL_GPL(dm_set_device_limits);
int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
- sector_t len, int mode, struct dm_dev **result)
+ sector_t len, fmode_t mode, struct dm_dev **result)
{
int r = __table_get_device(ti->table, ti, path,
start, len, mode, result);
@@ -887,7 +878,7 @@ struct list_head *dm_table_get_devices(struct dm_table *t)
return &t->devices;
}
-int dm_table_get_mode(struct dm_table *t)
+fmode_t dm_table_get_mode(struct dm_table *t)
{
return t->mode;
}
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
index bdec206c404..cdbf126ec10 100644
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -4,7 +4,7 @@
* This file is released under the GPL.
*/
-#include "dm.h"
+#include <linux/device-mapper.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 327de03a5bd..6963ad14840 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -21,7 +21,6 @@
#include <linux/idr.h>
#include <linux/hdreg.h>
#include <linux/blktrace_api.h>
-#include <linux/smp_lock.h>
#define DM_MSG_PREFIX "core"
@@ -76,7 +75,6 @@ union map_info *dm_get_mapinfo(struct bio *bio)
*/
struct dm_wq_req {
enum {
- DM_WQ_FLUSH_ALL,
DM_WQ_FLUSH_DEFERRED,
} type;
struct work_struct work;
@@ -151,40 +149,40 @@ static struct kmem_cache *_tio_cache;
static int __init local_init(void)
{
- int r;
+ int r = -ENOMEM;
/* allocate a slab for the dm_ios */
_io_cache = KMEM_CACHE(dm_io, 0);
if (!_io_cache)
- return -ENOMEM;
+ return r;
/* allocate a slab for the target ios */
_tio_cache = KMEM_CACHE(dm_target_io, 0);
- if (!_tio_cache) {
- kmem_cache_destroy(_io_cache);
- return -ENOMEM;
- }
+ if (!_tio_cache)
+ goto out_free_io_cache;
r = dm_uevent_init();
- if (r) {
- kmem_cache_destroy(_tio_cache);
- kmem_cache_destroy(_io_cache);
- return r;
- }
+ if (r)
+ goto out_free_tio_cache;
_major = major;
r = register_blkdev(_major, _name);
- if (r < 0) {
- kmem_cache_destroy(_tio_cache);
- kmem_cache_destroy(_io_cache);
- dm_uevent_exit();
- return r;
- }
+ if (r < 0)
+ goto out_uevent_exit;
if (!_major)
_major = r;
return 0;
+
+out_uevent_exit:
+ dm_uevent_exit();
+out_free_tio_cache:
+ kmem_cache_destroy(_tio_cache);
+out_free_io_cache:
+ kmem_cache_destroy(_io_cache);
+
+ return r;
}
static void local_exit(void)
@@ -249,13 +247,13 @@ static void __exit dm_exit(void)
/*
* Block device functions
*/
-static int dm_blk_open(struct inode *inode, struct file *file)
+static int dm_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mapped_device *md;
spin_lock(&_minor_lock);
- md = inode->i_bdev->bd_disk->private_data;
+ md = bdev->bd_disk->private_data;
if (!md)
goto out;
@@ -274,11 +272,9 @@ out:
return md ? 0 : -ENXIO;
}
-static int dm_blk_close(struct inode *inode, struct file *file)
+static int dm_blk_close(struct gendisk *disk, fmode_t mode)
{
- struct mapped_device *md;
-
- md = inode->i_bdev->bd_disk->private_data;
+ struct mapped_device *md = disk->private_data;
atomic_dec(&md->open_count);
dm_put(md);
return 0;
@@ -315,21 +311,14 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return dm_get_geometry(md, geo);
}
-static int dm_blk_ioctl(struct inode *inode, struct file *file,
+static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct mapped_device *md;
- struct dm_table *map;
+ struct mapped_device *md = bdev->bd_disk->private_data;
+ struct dm_table *map = dm_get_table(md);
struct dm_target *tgt;
int r = -ENOTTY;
- /* We don't really need this lock, but we do need 'inode'. */
- unlock_kernel();
-
- md = inode->i_bdev->bd_disk->private_data;
-
- map = dm_get_table(md);
-
if (!map || !dm_table_get_size(map))
goto out;
@@ -345,12 +334,11 @@ static int dm_blk_ioctl(struct inode *inode, struct file *file,
}
if (tgt->type->ioctl)
- r = tgt->type->ioctl(tgt, inode, file, cmd, arg);
+ r = tgt->type->ioctl(tgt, cmd, arg);
out:
dm_table_put(map);
- lock_kernel();
return r;
}
@@ -669,6 +657,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
clone->bi_size = to_bytes(len);
clone->bi_io_vec->bv_offset = offset;
clone->bi_io_vec->bv_len = clone->bi_size;
+ clone->bi_flags |= 1 << BIO_CLONED;
return clone;
}
@@ -1394,9 +1383,6 @@ static void dm_wq_work(struct work_struct *work)
down_write(&md->io_lock);
switch (req->type) {
- case DM_WQ_FLUSH_ALL:
- __merge_pushback_list(md);
- /* pass through */
case DM_WQ_FLUSH_DEFERRED:
__flush_deferred_io(md);
break;
@@ -1526,7 +1512,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
if (!md->suspended_bdev) {
DMWARN("bdget failed in dm_suspend");
r = -ENOMEM;
- goto flush_and_out;
+ goto out;
}
/*
@@ -1577,14 +1563,6 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
set_bit(DMF_SUSPENDED, &md->flags);
-flush_and_out:
- if (r && noflush)
- /*
- * Because there may be already I/Os in the pushback list,
- * flush them before return.
- */
- dm_queue_flush(md, DM_WQ_FLUSH_ALL, NULL);
-
out:
if (r && md->suspended_bdev) {
bdput(md->suspended_bdev);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index cd189da2b2f..0ade60cdef4 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -62,15 +62,6 @@ void dm_put_target_type(struct target_type *t);
int dm_target_iterate(void (*iter_func)(struct target_type *tt,
void *param), void *param);
-/*-----------------------------------------------------------------
- * Useful inlines.
- *---------------------------------------------------------------*/
-static inline int array_too_big(unsigned long fixed, unsigned long obj,
- unsigned long num)
-{
- return (num > (ULONG_MAX - fixed) / obj);
-}
-
int dm_split_args(int *argc, char ***argvp, char *input);
/*
diff --git a/drivers/md/md.c b/drivers/md/md.c
index aaa3d465de4..c1a837ca193 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1520,7 +1520,7 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared)
if (err) {
printk(KERN_ERR "md: could not bd_claim %s.\n",
bdevname(bdev, b));
- blkdev_put(bdev);
+ blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
return err;
}
if (!shared)
@@ -1536,7 +1536,7 @@ static void unlock_rdev(mdk_rdev_t *rdev)
if (!bdev)
MD_BUG();
bd_release(bdev);
- blkdev_put(bdev);
+ blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
}
void md_autodetect_dev(dev_t dev);
@@ -4785,7 +4785,7 @@ static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
-static int md_ioctl(struct inode *inode, struct file *file,
+static int md_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
int err = 0;
@@ -4823,7 +4823,7 @@ static int md_ioctl(struct inode *inode, struct file *file,
* Commands creating/starting a new array:
*/
- mddev = inode->i_bdev->bd_disk->private_data;
+ mddev = bdev->bd_disk->private_data;
if (!mddev) {
BUG();
@@ -4996,13 +4996,13 @@ abort:
return err;
}
-static int md_open(struct inode *inode, struct file *file)
+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 = inode->i_bdev->bd_disk->private_data;
+ mddev_t *mddev = bdev->bd_disk->private_data;
int err;
if ((err = mutex_lock_interruptible_nested(&mddev->reconfig_mutex, 1)))
@@ -5013,14 +5013,14 @@ static int md_open(struct inode *inode, struct file *file)
atomic_inc(&mddev->openers);
mddev_unlock(mddev);
- check_disk_change(inode->i_bdev);
+ check_disk_change(bdev);
out:
return err;
}
-static int md_release(struct inode *inode, struct file * file)
+static int md_release(struct gendisk *disk, fmode_t mode)
{
- mddev_t *mddev = inode->i_bdev->bd_disk->private_data;
+ mddev_t *mddev = disk->private_data;
BUG_ON(!mddev);
atomic_dec(&mddev->openers);
@@ -5048,7 +5048,7 @@ static struct block_device_operations md_fops =
.owner = THIS_MODULE,
.open = md_open,
.release = md_release,
- .ioctl = md_ioctl,
+ .locked_ioctl = md_ioctl,
.getgeo = md_getgeo,
.media_changed = md_media_changed,
.revalidate_disk= md_revalidate,
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 5b34c134aa2..127b0526a72 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -545,11 +545,11 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
if( VFL_TYPE_GRABBER == type ) {
vv->video_minor = vfd->minor;
INFO(("%s: registered device video%d [v4l2]\n",
- dev->name, vfd->minor & 0x1f));
+ dev->name, vfd->num));
} else {
vv->vbi_minor = vfd->minor;
INFO(("%s: registered device vbi%d [v4l2]\n",
- dev->name, vfd->minor & 0x1f));
+ dev->name, vfd->num));
}
*vid = vfd;
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 99be9e5c85f..fe0bd55977e 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -834,7 +834,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
* copying is done already, arg is a kernel pointer.
*/
-int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int __saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
@@ -1215,12 +1215,18 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
}
#endif
default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- saa7146_video_do_ioctl);
+ return v4l_compat_translate_ioctl(file, cmd, arg,
+ __saa7146_video_do_ioctl);
}
return 0;
}
+int saa7146_video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ return __saa7146_video_do_ioctl(file, cmd, arg);
+}
+
/*********************************************************************************/
/* buffer handling functions */
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
index 227642b044a..a8878244bb3 100644
--- a/drivers/media/common/tuners/mxl5005s.c
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -3481,7 +3481,9 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
}
ctrlVal = 0;
for (k = 0; k < state->MXL_Ctrl[i].size; k++)
- ctrlVal += state->MXL_Ctrl[i].val[k] * (1 << k);
+ ctrlVal += state->
+ MXL_Ctrl[i].val[k] *
+ (1 << k);
} else
return -1;
}
@@ -3581,7 +3583,7 @@ static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
static u32 MXL_Ceiling(u32 value, u32 resolution)
{
- return (value/resolution + (value % resolution > 0 ? 1 : 0));
+ return value / resolution + (value % resolution > 0 ? 1 : 0);
}
/* Retrieve the Initialzation Registers */
@@ -3910,7 +3912,10 @@ static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
static int mxl5005s_init(struct dvb_frontend *fe)
{
+ struct mxl5005s_state *state = fe->tuner_priv;
+
dprintk(1, "%s()\n", __func__);
+ state->current_mode = MXL_QAM;
return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ);
}
@@ -4092,7 +4097,6 @@ struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
state->frontend = fe;
state->config = config;
state->i2c = i2c;
- state->current_mode = MXL_QAM;
printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n",
config->i2c_address);
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index 2a1aac1cc75..fb3f3b3adab 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -493,6 +493,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FMD1216ME_MK3:
+ case TUNER_PHILIPS_FMD1216MEX_MK3:
case TUNER_LG_NTSC_TAPE:
case TUNER_PHILIPS_FM1256_IH3:
case TUNER_TCL_MF02GIP_5N:
@@ -767,6 +768,7 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
switch (priv->type) {
case TUNER_PHILIPS_FMD1216ME_MK3:
+ case TUNER_PHILIPS_FMD1216MEX_MK3:
if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
params->frequency >= 158870000)
buf[3] |= 0x08;
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
index 04961a1f44b..7c0bc064c00 100644
--- a/drivers/media/common/tuners/tuner-types.c
+++ b/drivers/media/common/tuners/tuner-types.c
@@ -946,7 +946,7 @@ static struct tuner_params tuner_tena_9533_di_params[] = {
},
};
-/* ------------ TUNER_PHILIPS_FMD1216ME_MK3 - Philips PAL ------------ */
+/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */
static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
{ 16 * 160.00 /*MHz*/, 0x86, 0x51, },
@@ -984,6 +984,27 @@ static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
},
};
+static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
+ .has_tda9887 = 1,
+ .port1_active = 1,
+ .port2_active = 1,
+ .port2_fm_high_sensitivity = 1,
+ .port2_invert_for_secam_lc = 1,
+ .port1_set_for_fm_mono = 1,
+ .radio_if = 1,
+ .fm_gain_normal = 1,
+ },
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
+ .iffreq = 16 * 36.125, /*MHz*/
+ },
+};
/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
@@ -1663,6 +1684,16 @@ struct tunertype tuners[] = {
.params = tuner_tcl_mf02gip_5n_params,
.count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
},
+ [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */
+ .name = "Philips FMD1216MEX MK3 Hybrid Tuner",
+ .params = tuner_philips_fmd1216mex_mk3_params,
+ .count = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params),
+ .min = 16 * 50.87,
+ .max = 16 * 858.00,
+ .stepsize = 166667,
+ .initdata = tua603x_agc112,
+ .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
+ },
};
EXPORT_SYMBOL(tuners);
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index f9c2bb917f5..e12d13e0cbe 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
static DEFINE_MUTEX(xc5000_list_mutex);
static LIST_HEAD(hybrid_tuner_instance_list);
-#define dprintk(level,fmt, arg...) if (debug >= level) \
+#define dprintk(level, fmt, arg...) if (debug >= level) \
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
@@ -138,11 +138,11 @@ struct xc5000_priv {
immediately the length of the following transaction.
*/
-typedef struct {
+struct XC_TV_STANDARD {
char *Name;
u16 AudioMode;
u16 VideoMode;
-} XC_TV_STANDARD;
+};
/* Tuner standards */
#define MN_NTSC_PAL_BTSC 0
@@ -169,7 +169,7 @@ typedef struct {
#define FM_Radio_INPUT2 21
#define FM_Radio_INPUT1 22
-static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
{"M/N-NTSC/PAL-A2", 0x0600, 0x8020},
{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
@@ -183,7 +183,7 @@ static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
{"D/K-PAL-NICAM", 0x0E80, 0x8009},
{"D/K-PAL-MONO", 0x1478, 0x8009},
{"D/K-SECAM-A2 DK1", 0x1200, 0x8009},
- {"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009},
+ {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009},
{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
{"L-SECAM-NICAM", 0x8E82, 0x0009},
{"L'-SECAM-NICAM", 0x8E82, 0x4009},
@@ -307,9 +307,10 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
unsigned int len, pos, index;
u8 buf[XC_MAX_I2C_WRITE_LENGTH];
- index=0;
- while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) {
- len = i2c_sequence[index]* 256 + i2c_sequence[index+1];
+ index = 0;
+ while ((i2c_sequence[index] != 0xFF) ||
+ (i2c_sequence[index + 1] != 0xFF)) {
+ len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
if (len == 0x0000) {
/* RESET command */
result = xc_reset(fe);
@@ -329,15 +330,17 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
buf[1] = i2c_sequence[index + 1];
pos = 2;
while (pos < len) {
- if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) {
- nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH;
- } else {
+ if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
+ nbytes_to_send =
+ XC_MAX_I2C_WRITE_LENGTH;
+ else
nbytes_to_send = (len - pos + 2);
+ for (i = 2; i < nbytes_to_send; i++) {
+ buf[i] = i2c_sequence[index + pos +
+ i - 2];
}
- for (i=2; i<nbytes_to_send; i++) {
- buf[i] = i2c_sequence[index + pos + i - 2];
- }
- result = xc_send_i2c_data(priv, buf, nbytes_to_send);
+ result = xc_send_i2c_data(priv, buf,
+ nbytes_to_send);
if (result != XC_RESULT_SUCCESS)
return result;
@@ -386,8 +389,7 @@ static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
- if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
- {
+ if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
rf_mode = XC_RF_MODE_CABLE;
printk(KERN_ERR
"%s(), Invalid mode, defaulting to CABLE",
@@ -560,13 +562,13 @@ static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
.flags = I2C_M_RD, .buf = buf, .len = len };
if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
- printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
+ printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len);
return -EREMOTEIO;
}
return 0;
}
-static int xc5000_fwupload(struct dvb_frontend* fe)
+static int xc5000_fwupload(struct dvb_frontend *fe)
{
struct xc5000_priv *priv = fe->tuner_priv;
const struct firmware *fw;
@@ -576,7 +578,8 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
XC5000_DEFAULT_FIRMWARE);
- ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev);
+ ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
+ &priv->i2c_props.adap->dev);
if (ret) {
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
ret = XC_RESULT_RESET_FAILURE;
@@ -592,7 +595,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
ret = XC_RESULT_RESET_FAILURE;
} else {
printk(KERN_INFO "xc5000: firmware upload\n");
- ret = xc_load_i2c_sequence(fe, fw->data );
+ ret = xc_load_i2c_sequence(fe, fw->data);
}
out:
@@ -651,7 +654,7 @@ static int xc5000_set_params(struct dvb_frontend *fe,
dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
- switch(params->u.vsb.modulation) {
+ switch (params->u.vsb.modulation) {
case VSB_8:
case VSB_16:
dprintk(1, "%s() VSB modulation\n", __func__);
@@ -748,42 +751,42 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
/* FIX ME: Some video standards may have several possible audio
standards. We simply default to one of them here.
*/
- if(params->std & V4L2_STD_MN) {
+ if (params->std & V4L2_STD_MN) {
/* default to BTSC audio standard */
priv->video_standard = MN_NTSC_PAL_BTSC;
goto tune_channel;
}
- if(params->std & V4L2_STD_PAL_BG) {
+ if (params->std & V4L2_STD_PAL_BG) {
/* default to NICAM audio standard */
priv->video_standard = BG_PAL_NICAM;
goto tune_channel;
}
- if(params->std & V4L2_STD_PAL_I) {
+ if (params->std & V4L2_STD_PAL_I) {
/* default to NICAM audio standard */
priv->video_standard = I_PAL_NICAM;
goto tune_channel;
}
- if(params->std & V4L2_STD_PAL_DK) {
+ if (params->std & V4L2_STD_PAL_DK) {
/* default to NICAM audio standard */
priv->video_standard = DK_PAL_NICAM;
goto tune_channel;
}
- if(params->std & V4L2_STD_SECAM_DK) {
+ if (params->std & V4L2_STD_SECAM_DK) {
/* default to A2 DK1 audio standard */
priv->video_standard = DK_SECAM_A2DK1;
goto tune_channel;
}
- if(params->std & V4L2_STD_SECAM_L) {
+ if (params->std & V4L2_STD_SECAM_L) {
priv->video_standard = L_SECAM_NICAM;
goto tune_channel;
}
- if(params->std & V4L2_STD_SECAM_LC) {
+ if (params->std & V4L2_STD_SECAM_LC) {
priv->video_standard = LC_SECAM_NICAM;
goto tune_channel;
}
@@ -791,7 +794,7 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
tune_channel:
ret = xc_SetSignalSource(priv, priv->rf_mode);
if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR
+ printk(KERN_ERR
"xc5000: xc_SetSignalSource(%d) failed\n",
priv->rf_mode);
return -EREMOTEIO;
@@ -863,7 +866,7 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
* I2C transactions until calibration is complete. This way we
* don't have to rely on clock stretching working.
*/
- xc_wait( 100 );
+ xc_wait(100);
/* Default to "CABLE" mode */
ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
@@ -885,15 +888,13 @@ static int xc5000_sleep(struct dvb_frontend *fe)
*/
ret = xc_shutdown(priv);
- if(ret != XC_RESULT_SUCCESS) {
+ if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR
"xc5000: %s() unable to shutdown tuner\n",
__func__);
return -EREMOTEIO;
- }
- else {
+ } else
return XC_RESULT_SUCCESS;
- }
}
static int xc5000_init(struct dvb_frontend *fe)
@@ -989,7 +990,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
goto fail;
- switch(id) {
+ switch (id) {
case XC_PRODUCT_ID_FW_LOADED:
printk(KERN_INFO
"xc5000: Successfully identified at address 0x%02x\n",
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index cf1a558e0e7..f4c146698a0 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -45,17 +45,17 @@ struct xc5000_config {
#if defined(CONFIG_MEDIA_TUNER_XC5000) || \
(defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
-extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct xc5000_config *cfg);
#else
-static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct xc5000_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_MEDIA_TUNER_XC5000
+#endif
-#endif // __XC5000_H__
+#endif
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index f7321448b4b..14e627ef646 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -595,6 +595,18 @@ static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb)
dm1105dvb_dma_unmap(dm1105dvb);
}
+static struct stv0299_config sharp_z0194a_config = {
+ .demod_address = 0x68,
+ .inittab = sharp_z0194a_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .skip_reinit = 0,
+ .lock_output = STV0299_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = sharp_z0194a_set_symbol_rate,
+};
+
static struct stv0288_config earda_config = {
.demod_address = 0x68,
.min_delay_ms = 100,
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index f170e822fad..5689d1f1d44 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -47,6 +47,7 @@ static int dvb_shutdown_timeout;
static int dvb_force_auto_inversion;
static int dvb_override_tune_delay;
static int dvb_powerdown_on_sleep = 1;
+static int dvb_mfe_wait_time = 5;
module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
@@ -58,6 +59,8 @@ module_param(dvb_override_tune_delay, int, 0644);
MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
module_param(dvb_powerdown_on_sleep, int, 0644);
MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
+module_param(dvb_mfe_wait_time, int, 0644);
+MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
#define dprintk if (dvb_frontend_debug) printk
@@ -212,8 +215,9 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
static void dvb_frontend_init(struct dvb_frontend *fe)
{
- dprintk ("DVB: initialising frontend %i (%s)...\n",
+ dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
fe->dvb->num,
+ fe->id,
fe->ops.info.name);
if (fe->ops.init)
@@ -686,7 +690,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
mb();
fe_thread = kthread_run(dvb_frontend_thread, fe,
- "kdvb-fe-%i", fe->dvb->num);
+ "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
if (IS_ERR(fe_thread)) {
ret = PTR_ERR(fe_thread);
printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
@@ -710,8 +714,8 @@ static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
*freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
if (*freq_min == 0 || *freq_max == 0)
- printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",
- fe->dvb->num);
+ printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
+ fe->dvb->num,fe->id);
}
static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
@@ -724,8 +728,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
if ((freq_min && parms->frequency < freq_min) ||
(freq_max && parms->frequency > freq_max)) {
- printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
- fe->dvb->num, parms->frequency, freq_min, freq_max);
+ printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
+ fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max);
return -EINVAL;
}
@@ -735,8 +739,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
(fe->ops.info.symbol_rate_max &&
parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
- printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
- fe->dvb->num, parms->u.qpsk.symbol_rate,
+ printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
+ fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate,
fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
return -EINVAL;
}
@@ -746,8 +750,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
(fe->ops.info.symbol_rate_max &&
parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
- printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
- fe->dvb->num, parms->u.qam.symbol_rate,
+ printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
+ fe->dvb->num, fe->id, parms->u.qam.symbol_rate,
fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
return -EINVAL;
}
@@ -899,30 +903,30 @@ void dtv_property_dump(struct dtv_property *tvp)
int i;
if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
- printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n",
+ printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
__func__, tvp->cmd);
return;
}
- printk("%s() tvp.cmd = 0x%08x (%s)\n"
- ,__FUNCTION__
+ dprintk("%s() tvp.cmd = 0x%08x (%s)\n"
+ ,__func__
,tvp->cmd
,dtv_cmds[ tvp->cmd ].name);
if(dtv_cmds[ tvp->cmd ].buffer) {
- printk("%s() tvp.u.buffer.len = 0x%02x\n"
- ,__FUNCTION__
+ dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
+ ,__func__
,tvp->u.buffer.len);
for(i = 0; i < tvp->u.buffer.len; i++)
- printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
- ,__FUNCTION__
+ dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+ ,__func__
,i
,tvp->u.buffer.data[i]);
} else
- printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
+ dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
}
int is_legacy_delivery_system(fe_delivery_system_t s)
@@ -942,8 +946,6 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- printk("%s()\n", __FUNCTION__);
-
c->frequency = p->frequency;
c->inversion = p->inversion;
@@ -998,27 +1000,25 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dvb_frontend_parameters *p = &fepriv->parameters;
- printk("%s()\n", __FUNCTION__);
-
p->frequency = c->frequency;
p->inversion = c->inversion;
switch (fe->ops.info.type) {
case FE_QPSK:
- printk("%s() Preparing QPSK req\n", __FUNCTION__);
+ dprintk("%s() Preparing QPSK req\n", __func__);
p->u.qpsk.symbol_rate = c->symbol_rate;
p->u.qpsk.fec_inner = c->fec_inner;
c->delivery_system = SYS_DVBS;
break;
case FE_QAM:
- printk("%s() Preparing QAM req\n", __FUNCTION__);
+ dprintk("%s() Preparing QAM req\n", __func__);
p->u.qam.symbol_rate = c->symbol_rate;
p->u.qam.fec_inner = c->fec_inner;
p->u.qam.modulation = c->modulation;
c->delivery_system = SYS_DVBC_ANNEX_AC;
break;
case FE_OFDM:
- printk("%s() Preparing OFDM req\n", __FUNCTION__);
+ dprintk("%s() Preparing OFDM req\n", __func__);
if (c->bandwidth_hz == 6000000)
p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
else if (c->bandwidth_hz == 7000000)
@@ -1036,7 +1036,7 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
c->delivery_system = SYS_DVBT;
break;
case FE_ATSC:
- printk("%s() Preparing VSB req\n", __FUNCTION__);
+ dprintk("%s() Preparing VSB req\n", __func__);
p->u.vsb.modulation = c->modulation;
if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
c->delivery_system = SYS_ATSC;
@@ -1055,14 +1055,13 @@ void dtv_property_adv_params_sync(struct dvb_frontend *fe)
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dvb_frontend_parameters *p = &fepriv->parameters;
- printk("%s()\n", __FUNCTION__);
-
p->frequency = c->frequency;
p->inversion = c->inversion;
switch(c->modulation) {
case PSK_8:
case APSK_16:
+ case APSK_32:
case QPSK:
p->u.qpsk.symbol_rate = c->symbol_rate;
p->u.qpsk.fec_inner = c->fec_inner;
@@ -1089,19 +1088,17 @@ void dtv_property_cache_submit(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- printk("%s()\n", __FUNCTION__);
-
/* For legacy delivery systems we don't need the delivery_system to
* be specified, but we populate the older structures from the cache
* so we can call set_frontend on older drivers.
*/
if(is_legacy_delivery_system(c->delivery_system)) {
- printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation);
+ dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation);
dtv_property_legacy_params_sync(fe);
} else {
- printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation);
+ dprintk("%s() adv, modulation = %d\n", __func__, c->modulation);
/* For advanced delivery systems / modulation types ...
* we seed the lecacy dvb_frontend_parameters structure
@@ -1123,8 +1120,6 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
{
int r = 0;
- printk("%s()\n", __FUNCTION__);
-
dtv_property_dump(tvp);
/* Allow the frontend to validate incoming properties */
@@ -1198,7 +1193,6 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
{
int r = 0;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
- printk("%s()\n", __FUNCTION__);
dtv_property_dump(tvp);
/* Allow the frontend to validate incoming properties */
@@ -1213,7 +1207,7 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
/* Reset a cache of data specific to the frontend here. This does
* not effect hardware.
*/
- printk("%s() Flushing property cache\n", __FUNCTION__);
+ dprintk("%s() Flushing property cache\n", __func__);
memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));
fe->dtv_property_cache.state = tvp->cmd;
fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
@@ -1224,7 +1218,7 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
* ioctl.
*/
fe->dtv_property_cache.state = tvp->cmd;
- printk("%s() Finalised property cache\n", __FUNCTION__);
+ dprintk("%s() Finalised property cache\n", __func__);
dtv_property_cache_submit(fe);
r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
@@ -1335,12 +1329,10 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
dprintk("%s\n", __func__);
if(cmd == FE_SET_PROPERTY) {
- printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
-
tvps = (struct dtv_properties __user *)parg;
- printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
- printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+ dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+ dprintk("%s() properties.props = %p\n", __func__, tvps->props);
/* Put an arbitrary limit on the number of messages that can
* be sent at once */
@@ -1364,18 +1356,16 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
err |= (tvp + i)->result;
}
- if(fe->dtv_property_cache.state == DTV_TUNE) {
- printk("%s() Property cache is full, tuning\n", __FUNCTION__);
- }
+ if(fe->dtv_property_cache.state == DTV_TUNE)
+ dprintk("%s() Property cache is full, tuning\n", __func__);
} else
if(cmd == FE_GET_PROPERTY) {
- printk("%s() FE_GET_PROPERTY\n", __FUNCTION__);
tvps = (struct dtv_properties __user *)parg;
- printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
- printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+ dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+ dprintk("%s() properties.props = %p\n", __func__, tvps->props);
/* Put an arbitrary limit on the number of messages that can
* be sent at once */
@@ -1704,13 +1694,53 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dvb_adapter *adapter = fe->dvb;
int ret;
dprintk ("%s\n", __func__);
+ if (adapter->mfe_shared) {
+ mutex_lock (&adapter->mfe_lock);
+
+ if (adapter->mfe_dvbdev == NULL)
+ adapter->mfe_dvbdev = dvbdev;
+
+ else if (adapter->mfe_dvbdev != dvbdev) {
+ struct dvb_device
+ *mfedev = adapter->mfe_dvbdev;
+ struct dvb_frontend
+ *mfe = mfedev->priv;
+ struct dvb_frontend_private
+ *mfepriv = mfe->frontend_priv;
+ int mferetry = (dvb_mfe_wait_time << 1);
+
+ mutex_unlock (&adapter->mfe_lock);
+ while (mferetry-- && (mfedev->users != -1 ||
+ mfepriv->thread != NULL)) {
+ if(msleep_interruptible(500)) {
+ if(signal_pending(current))
+ return -EINTR;
+ }
+ }
+
+ mutex_lock (&adapter->mfe_lock);
+ if(adapter->mfe_dvbdev != dvbdev) {
+ mfedev = adapter->mfe_dvbdev;
+ mfe = mfedev->priv;
+ mfepriv = mfe->frontend_priv;
+ if (mfedev->users != -1 ||
+ mfepriv->thread != NULL) {
+ mutex_unlock (&adapter->mfe_lock);
+ return -EBUSY;
+ }
+ adapter->mfe_dvbdev = dvbdev;
+ }
+ }
+ }
+
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
- return ret;
+ goto err0;
}
if ((ret = dvb_generic_open (inode, file)) < 0)
@@ -1730,6 +1760,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
fepriv->events.eventr = fepriv->events.eventw = 0;
}
+ if (adapter->mfe_shared)
+ mutex_unlock (&adapter->mfe_lock);
return ret;
err2:
@@ -1737,6 +1769,9 @@ err2:
err1:
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
fe->ops.ts_bus_ctrl(fe, 0);
+err0:
+ if (adapter->mfe_shared)
+ mutex_unlock (&adapter->mfe_lock);
return ret;
}
@@ -1806,8 +1841,9 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
fe->dvb = dvb;
fepriv->inversion = INVERSION_OFF;
- printk ("DVB: registering frontend %i (%s)...\n",
+ printk ("DVB: registering adapter %i frontend %i (%s)...\n",
fe->dvb->num,
+ fe->id,
fe->ops.info.name);
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 3055301ff3c..db4a63b0a32 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -222,6 +222,7 @@ struct dvb_frontend {
struct dtv_frontend_properties dtv_property_cache;
#define DVB_FRONTEND_COMPONENT_TUNER 0
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
+ int id;
};
extern int dvb_register_frontend(struct dvb_adapter *dvb,
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 665776d72a4..a113744a56c 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -326,6 +326,9 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
adap->name = name;
adap->module = module;
adap->device = device;
+ adap->mfe_shared = 0;
+ adap->mfe_dvbdev = NULL;
+ mutex_init (&adap->mfe_lock);
list_add_tail (&adap->list_head, &dvb_adapter_list);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 89d12dc477a..574e336bac3 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -62,6 +62,10 @@ struct dvb_adapter {
struct device *device;
struct module *module;
+
+ int mfe_shared; /* indicates mutually exclusive frontends */
+ struct dvb_device *mfe_dvbdev; /* frontend device in use */
+ struct mutex mfe_lock; /* access lock for thread creation */
};
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index ca53df61caa..6286fbbe7fb 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -422,6 +422,18 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
return 0;
}
+static struct stv0299_config sharp_z0194a_config = {
+ .demod_address = 0x68,
+ .inittab = sharp_z0194a_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .skip_reinit = 0,
+ .lock_output = STV0299_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = sharp_z0194a_set_symbol_rate,
+};
+
static struct cx24116_config dw2104_config = {
.demod_address = 0x55,
.mpg_clk_pos_pol = 0x01,
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 9430e03dba6..5d1abe34bdd 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -34,13 +34,12 @@
#include "dvb_frontend.h"
#include "cx22702.h"
-
struct cx22702_state {
- struct i2c_adapter* i2c;
+ struct i2c_adapter *i2c;
/* configuration settings */
- const struct cx22702_config* config;
+ const struct cx22702_config *config;
struct dvb_frontend frontend;
@@ -49,10 +48,13 @@ struct cx22702_state {
};
static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
#define dprintk if (debug) printk
/* Register values to initialise the demod */
-static u8 init_tab [] = {
+static u8 init_tab[] = {
0x00, 0x00, /* Stop aquisition */
0x0B, 0x06,
0x09, 0x01,
@@ -80,65 +82,67 @@ static u8 init_tab [] = {
0xfd, 0x00,
};
-static int cx22702_writereg (struct cx22702_state* state, u8 reg, u8 data)
+static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
{
int ret;
- u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = {
+ .addr = state->config->demod_address, .flags = 0,
+ .buf = buf, .len = 2 };
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
- printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+ printk(KERN_ERR
+ "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
__func__, reg, data, ret);
return (ret != 1) ? -1 : 0;
}
-static u8 cx22702_readreg (struct cx22702_state* state, u8 reg)
+static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
{
int ret;
- u8 b0 [] = { reg };
- u8 b1 [] = { 0 };
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
- struct i2c_msg msg [] = {
- { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
- { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+ struct i2c_msg msg[] = {
+ { .addr = state->config->demod_address, .flags = 0,
+ .buf = b0, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD,
+ .buf = b1, .len = 1 } };
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2)
- printk("%s: readreg error (ret == %i)\n", __func__, ret);
+ printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+ __func__, ret);
return b1[0];
}
-static int cx22702_set_inversion (struct cx22702_state *state, int inversion)
+static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
{
u8 val;
switch (inversion) {
-
- case INVERSION_AUTO:
- return -EOPNOTSUPP;
-
- case INVERSION_ON:
- val = cx22702_readreg (state, 0x0C);
- return cx22702_writereg (state, 0x0C, val | 0x01);
-
- case INVERSION_OFF:
- val = cx22702_readreg (state, 0x0C);
- return cx22702_writereg (state, 0x0C, val & 0xfe);
-
- default:
- return -EINVAL;
-
+ case INVERSION_AUTO:
+ return -EOPNOTSUPP;
+ case INVERSION_ON:
+ val = cx22702_readreg(state, 0x0C);
+ return cx22702_writereg(state, 0x0C, val | 0x01);
+ case INVERSION_OFF:
+ val = cx22702_readreg(state, 0x0C);
+ return cx22702_writereg(state, 0x0C, val & 0xfe);
+ default:
+ return -EINVAL;
}
}
/* Retrieve the demod settings */
-static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p)
+static int cx22702_get_tps(struct cx22702_state *state,
+ struct dvb_ofdm_parameters *p)
{
u8 val;
@@ -146,180 +150,281 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet
if (!(cx22702_readreg(state, 0x0A) & 0x20))
return -EAGAIN;
- val = cx22702_readreg (state, 0x01);
- switch( (val&0x18)>>3) {
- case 0: p->constellation = QPSK; break;
- case 1: p->constellation = QAM_16; break;
- case 2: p->constellation = QAM_64; break;
+ val = cx22702_readreg(state, 0x01);
+ switch ((val & 0x18) >> 3) {
+ case 0:
+ p->constellation = QPSK;
+ break;
+ case 1:
+ p->constellation = QAM_16;
+ break;
+ case 2:
+ p->constellation = QAM_64;
+ break;
}
- switch( val&0x07 ) {
- case 0: p->hierarchy_information = HIERARCHY_NONE; break;
- case 1: p->hierarchy_information = HIERARCHY_1; break;
- case 2: p->hierarchy_information = HIERARCHY_2; break;
- case 3: p->hierarchy_information = HIERARCHY_4; break;
+ switch (val & 0x07) {
+ case 0:
+ p->hierarchy_information = HIERARCHY_NONE;
+ break;
+ case 1:
+ p->hierarchy_information = HIERARCHY_1;
+ break;
+ case 2:
+ p->hierarchy_information = HIERARCHY_2;
+ break;
+ case 3:
+ p->hierarchy_information = HIERARCHY_4;
+ break;
}
- val = cx22702_readreg (state, 0x02);
- switch( (val&0x38)>>3 ) {
- case 0: p->code_rate_HP = FEC_1_2; break;
- case 1: p->code_rate_HP = FEC_2_3; break;
- case 2: p->code_rate_HP = FEC_3_4; break;
- case 3: p->code_rate_HP = FEC_5_6; break;
- case 4: p->code_rate_HP = FEC_7_8; break;
+ val = cx22702_readreg(state, 0x02);
+ switch ((val & 0x38) >> 3) {
+ case 0:
+ p->code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ p->code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ p->code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ p->code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ p->code_rate_HP = FEC_7_8;
+ break;
}
- switch( val&0x07 ) {
- case 0: p->code_rate_LP = FEC_1_2; break;
- case 1: p->code_rate_LP = FEC_2_3; break;
- case 2: p->code_rate_LP = FEC_3_4; break;
- case 3: p->code_rate_LP = FEC_5_6; break;
- case 4: p->code_rate_LP = FEC_7_8; break;
+ switch (val & 0x07) {
+ case 0:
+ p->code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ p->code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ p->code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ p->code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ p->code_rate_LP = FEC_7_8;
+ break;
}
-
- val = cx22702_readreg (state, 0x03);
- switch( (val&0x0c)>>2 ) {
- case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
- case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
- case 2: p->guard_interval = GUARD_INTERVAL_1_8; break;
- case 3: p->guard_interval = GUARD_INTERVAL_1_4; break;
+ val = cx22702_readreg(state, 0x03);
+ switch ((val & 0x0c) >> 2) {
+ case 0:
+ p->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ p->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ p->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ p->guard_interval = GUARD_INTERVAL_1_4;
+ break;
}
- switch( val&0x03 ) {
- case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
- case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+ switch (val & 0x03) {
+ case 0:
+ p->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ p->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
}
return 0;
}
-static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
- struct cx22702_state* state = fe->demodulator_priv;
- dprintk ("%s(%d)\n", __func__, enable);
+ struct cx22702_state *state = fe->demodulator_priv;
+ dprintk("%s(%d)\n", __func__, enable);
if (enable)
- return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe);
+ return cx22702_writereg(state, 0x0D,
+ cx22702_readreg(state, 0x0D) & 0xfe);
else
- return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1);
+ return cx22702_writereg(state, 0x0D,
+ cx22702_readreg(state, 0x0D) | 1);
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22702_set_tps(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
u8 val;
- struct cx22702_state* state = fe->demodulator_priv;
+ struct cx22702_state *state = fe->demodulator_priv;
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe, p);
- if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
}
/* set inversion */
- cx22702_set_inversion (state, p->inversion);
+ cx22702_set_inversion(state, p->inversion);
/* set bandwidth */
- switch(p->u.ofdm.bandwidth) {
+ switch (p->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
- cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20 );
+ cx22702_writereg(state, 0x0C,
+ (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20);
break;
case BANDWIDTH_7_MHZ:
- cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10 );
+ cx22702_writereg(state, 0x0C,
+ (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10);
break;
case BANDWIDTH_8_MHZ:
- cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf );
+ cx22702_writereg(state, 0x0C,
+ cx22702_readreg(state, 0x0C) & 0xcf);
break;
default:
- dprintk ("%s: invalid bandwidth\n",__func__);
+ dprintk("%s: invalid bandwidth\n", __func__);
return -EINVAL;
}
-
- p->u.ofdm.code_rate_LP = FEC_AUTO; //temp hack as manual not working
+ p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
/* use auto configuration? */
- if((p->u.ofdm.hierarchy_information==HIERARCHY_AUTO) ||
- (p->u.ofdm.constellation==QAM_AUTO) ||
- (p->u.ofdm.code_rate_HP==FEC_AUTO) ||
- (p->u.ofdm.code_rate_LP==FEC_AUTO) ||
- (p->u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) ||
- (p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) {
+ if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) ||
+ (p->u.ofdm.constellation == QAM_AUTO) ||
+ (p->u.ofdm.code_rate_HP == FEC_AUTO) ||
+ (p->u.ofdm.code_rate_LP == FEC_AUTO) ||
+ (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) ||
+ (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) {
/* TPS Source - use hardware driven values */
cx22702_writereg(state, 0x06, 0x10);
cx22702_writereg(state, 0x07, 0x9);
cx22702_writereg(state, 0x08, 0xC1);
- cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc );
- cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
+ cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B)
+ & 0xfc);
+ cx22702_writereg(state, 0x0C,
+ (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */
- dprintk("%s: Autodetecting\n",__func__);
+ dprintk("%s: Autodetecting\n", __func__);
return 0;
}
/* manually programmed values */
- val=0;
- switch(p->u.ofdm.constellation) {
- case QPSK: val = (val&0xe7); break;
- case QAM_16: val = (val&0xe7)|0x08; break;
- case QAM_64: val = (val&0xe7)|0x10; break;
- default:
- dprintk ("%s: invalid constellation\n",__func__);
- return -EINVAL;
+ val = 0;
+ switch (p->u.ofdm.constellation) {
+ case QPSK:
+ val = (val & 0xe7);
+ break;
+ case QAM_16:
+ val = (val & 0xe7) | 0x08;
+ break;
+ case QAM_64:
+ val = (val & 0xe7) | 0x10;
+ break;
+ default:
+ dprintk("%s: invalid constellation\n", __func__);
+ return -EINVAL;
}
- switch(p->u.ofdm.hierarchy_information) {
- case HIERARCHY_NONE: val = (val&0xf8); break;
- case HIERARCHY_1: val = (val&0xf8)|1; break;
- case HIERARCHY_2: val = (val&0xf8)|2; break;
- case HIERARCHY_4: val = (val&0xf8)|3; break;
- default:
- dprintk ("%s: invalid hierarchy\n",__func__);
- return -EINVAL;
+ switch (p->u.ofdm.hierarchy_information) {
+ case HIERARCHY_NONE:
+ val = (val & 0xf8);
+ break;
+ case HIERARCHY_1:
+ val = (val & 0xf8) | 1;
+ break;
+ case HIERARCHY_2:
+ val = (val & 0xf8) | 2;
+ break;
+ case HIERARCHY_4:
+ val = (val & 0xf8) | 3;
+ break;
+ default:
+ dprintk("%s: invalid hierarchy\n", __func__);
+ return -EINVAL;
}
- cx22702_writereg (state, 0x06, val);
-
- val=0;
- switch(p->u.ofdm.code_rate_HP) {
- case FEC_NONE:
- case FEC_1_2: val = (val&0xc7); break;
- case FEC_2_3: val = (val&0xc7)|0x08; break;
- case FEC_3_4: val = (val&0xc7)|0x10; break;
- case FEC_5_6: val = (val&0xc7)|0x18; break;
- case FEC_7_8: val = (val&0xc7)|0x20; break;
- default:
- dprintk ("%s: invalid code_rate_HP\n",__func__);
- return -EINVAL;
+ cx22702_writereg(state, 0x06, val);
+
+ val = 0;
+ switch (p->u.ofdm.code_rate_HP) {
+ case FEC_NONE:
+ case FEC_1_2:
+ val = (val & 0xc7);
+ break;
+ case FEC_2_3:
+ val = (val & 0xc7) | 0x08;
+ break;
+ case FEC_3_4:
+ val = (val & 0xc7) | 0x10;
+ break;
+ case FEC_5_6:
+ val = (val & 0xc7) | 0x18;
+ break;
+ case FEC_7_8:
+ val = (val & 0xc7) | 0x20;
+ break;
+ default:
+ dprintk("%s: invalid code_rate_HP\n", __func__);
+ return -EINVAL;
}
- switch(p->u.ofdm.code_rate_LP) {
- case FEC_NONE:
- case FEC_1_2: val = (val&0xf8); break;
- case FEC_2_3: val = (val&0xf8)|1; break;
- case FEC_3_4: val = (val&0xf8)|2; break;
- case FEC_5_6: val = (val&0xf8)|3; break;
- case FEC_7_8: val = (val&0xf8)|4; break;
- default:
- dprintk ("%s: invalid code_rate_LP\n",__func__);
- return -EINVAL;
+ switch (p->u.ofdm.code_rate_LP) {
+ case FEC_NONE:
+ case FEC_1_2:
+ val = (val & 0xf8);
+ break;
+ case FEC_2_3:
+ val = (val & 0xf8) | 1;
+ break;
+ case FEC_3_4:
+ val = (val & 0xf8) | 2;
+ break;
+ case FEC_5_6:
+ val = (val & 0xf8) | 3;
+ break;
+ case FEC_7_8:
+ val = (val & 0xf8) | 4;
+ break;
+ default:
+ dprintk("%s: invalid code_rate_LP\n", __func__);
+ return -EINVAL;
}
- cx22702_writereg (state, 0x07, val);
-
- val=0;
- switch(p->u.ofdm.guard_interval) {
- case GUARD_INTERVAL_1_32: val = (val&0xf3); break;
- case GUARD_INTERVAL_1_16: val = (val&0xf3)|0x04; break;
- case GUARD_INTERVAL_1_8: val = (val&0xf3)|0x08; break;
- case GUARD_INTERVAL_1_4: val = (val&0xf3)|0x0c; break;
- default:
- dprintk ("%s: invalid guard_interval\n",__func__);
- return -EINVAL;
+ cx22702_writereg(state, 0x07, val);
+
+ val = 0;
+ switch (p->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32:
+ val = (val & 0xf3);
+ break;
+ case GUARD_INTERVAL_1_16:
+ val = (val & 0xf3) | 0x04;
+ break;
+ case GUARD_INTERVAL_1_8:
+ val = (val & 0xf3) | 0x08;
+ break;
+ case GUARD_INTERVAL_1_4:
+ val = (val & 0xf3) | 0x0c;
+ break;
+ default:
+ dprintk("%s: invalid guard_interval\n", __func__);
+ return -EINVAL;
}
- switch(p->u.ofdm.transmission_mode) {
- case TRANSMISSION_MODE_2K: val = (val&0xfc); break;
- case TRANSMISSION_MODE_8K: val = (val&0xfc)|1; break;
- default:
- dprintk ("%s: invalid transmission_mode\n",__func__);
- return -EINVAL;
+ switch (p->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ val = (val & 0xfc);
+ break;
+ case TRANSMISSION_MODE_8K:
+ val = (val & 0xfc) | 1;
+ break;
+ default:
+ dprintk("%s: invalid transmission_mode\n", __func__);
+ return -EINVAL;
}
cx22702_writereg(state, 0x08, val);
- cx22702_writereg(state, 0x0B, (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02 );
- cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
+ cx22702_writereg(state, 0x0B,
+ (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02);
+ cx22702_writereg(state, 0x0C,
+ (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
/* Begin channel aquisition */
cx22702_writereg(state, 0x00, 0x01);
@@ -329,109 +434,111 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
/* Reset the demod hardware and reset all of the configuration registers
to a default state. */
-static int cx22702_init (struct dvb_frontend* fe)
+static int cx22702_init(struct dvb_frontend *fe)
{
int i;
- struct cx22702_state* state = fe->demodulator_priv;
+ struct cx22702_state *state = fe->demodulator_priv;
- cx22702_writereg (state, 0x00, 0x02);
+ cx22702_writereg(state, 0x00, 0x02);
msleep(10);
- for (i=0; i<sizeof(init_tab); i+=2)
- cx22702_writereg (state, init_tab[i], init_tab[i+1]);
+ for (i = 0; i < ARRAY_SIZE(init_tab); i += 2)
+ cx22702_writereg(state, init_tab[i], init_tab[i + 1]);
- cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
+ cx22702_writereg(state, 0xf8, (state->config->output_mode << 1)
+ & 0x02);
cx22702_i2c_gate_ctrl(fe, 0);
return 0;
}
-static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
- struct cx22702_state* state = fe->demodulator_priv;
+ struct cx22702_state *state = fe->demodulator_priv;
u8 reg0A;
u8 reg23;
*status = 0;
- reg0A = cx22702_readreg (state, 0x0A);
- reg23 = cx22702_readreg (state, 0x23);
+ reg0A = cx22702_readreg(state, 0x0A);
+ reg23 = cx22702_readreg(state, 0x23);
- dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
- ,__func__,reg0A,reg23);
+ dprintk("%s: status demod=0x%02x agc=0x%02x\n"
+ , __func__, reg0A, reg23);
- if(reg0A & 0x10) {
+ if (reg0A & 0x10) {
*status |= FE_HAS_LOCK;
*status |= FE_HAS_VITERBI;
*status |= FE_HAS_SYNC;
}
- if(reg0A & 0x20)
+ if (reg0A & 0x20)
*status |= FE_HAS_CARRIER;
- if(reg23 < 0xf0)
+ if (reg23 < 0xf0)
*status |= FE_HAS_SIGNAL;
return 0;
}
-static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber)
+static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- struct cx22702_state* state = fe->demodulator_priv;
+ struct cx22702_state *state = fe->demodulator_priv;
- if(cx22702_readreg (state, 0xE4) & 0x02) {
+ if (cx22702_readreg(state, 0xE4) & 0x02) {
/* Realtime statistics */
- *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
- | (cx22702_readreg (state, 0xDF)&0x7F);
+ *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
+ | (cx22702_readreg(state, 0xDF) & 0x7F);
} else {
/* Averagtine statistics */
- *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
- | cx22702_readreg (state, 0xDF);
+ *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
+ | cx22702_readreg(state, 0xDF);
}
return 0;
}
-static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+static int cx22702_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
{
- struct cx22702_state* state = fe->demodulator_priv;
+ struct cx22702_state *state = fe->demodulator_priv;
u16 rs_ber = 0;
- rs_ber = cx22702_readreg (state, 0x23);
+ rs_ber = cx22702_readreg(state, 0x23);
*signal_strength = (rs_ber << 8) | rs_ber;
return 0;
}
-static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr)
+static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
{
- struct cx22702_state* state = fe->demodulator_priv;
+ struct cx22702_state *state = fe->demodulator_priv;
- u16 rs_ber=0;
- if(cx22702_readreg (state, 0xE4) & 0x02) {
+ u16 rs_ber = 0;
+ if (cx22702_readreg(state, 0xE4) & 0x02) {
/* Realtime statistics */
- rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
- | (cx22702_readreg (state, 0xDF)& 0x7F);
+ rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
+ | (cx22702_readreg(state, 0xDF) & 0x7F);
} else {
/* Averagine statistics */
- rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 8
- | cx22702_readreg (state, 0xDF);
+ rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8
+ | cx22702_readreg(state, 0xDF);
}
*snr = ~rs_ber;
return 0;
}
-static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
- struct cx22702_state* state = fe->demodulator_priv;
+ struct cx22702_state *state = fe->demodulator_priv;
u8 _ucblocks;
/* RS Uncorrectable Packet Count then reset */
- _ucblocks = cx22702_readreg (state, 0xE3);
+ _ucblocks = cx22702_readreg(state, 0xE3);
if (state->prevUCBlocks < _ucblocks)
*ucblocks = (_ucblocks - state->prevUCBlocks);
else
@@ -441,34 +548,36 @@ static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22702_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
- struct cx22702_state* state = fe->demodulator_priv;
+ struct cx22702_state *state = fe->demodulator_priv;
- u8 reg0C = cx22702_readreg (state, 0x0C);
+ u8 reg0C = cx22702_readreg(state, 0x0C);
p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
- return cx22702_get_tps (state, &p->u.ofdm);
+ return cx22702_get_tps(state, &p->u.ofdm);
}
-static int cx22702_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+static int cx22702_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1000;
return 0;
}
-static void cx22702_release(struct dvb_frontend* fe)
+static void cx22702_release(struct dvb_frontend *fe)
{
- struct cx22702_state* state = fe->demodulator_priv;
+ struct cx22702_state *state = fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops cx22702_ops;
-struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
- struct i2c_adapter* i2c)
+struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
+ struct i2c_adapter *i2c)
{
- struct cx22702_state* state = NULL;
+ struct cx22702_state *state = NULL;
/* allocate memory for the internal state */
state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
@@ -485,7 +594,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
goto error;
/* create dvb_frontend */
- memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &cx22702_ops,
+ sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -493,6 +603,7 @@ error:
kfree(state);
return NULL;
}
+EXPORT_SYMBOL(cx22702_attach);
static struct dvb_frontend_ops cx22702_ops = {
@@ -525,11 +636,6 @@ static struct dvb_frontend_ops cx22702_ops = {
.read_ucblocks = cx22702_read_ucblocks,
};
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(cx22702_attach);
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index b1e465c6c2c..f154e1f428e 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -30,8 +30,7 @@
#include <linux/dvb/frontend.h>
-struct cx22702_config
-{
+struct cx22702_config {
/* the demodulator's i2c address */
u8 demod_address;
@@ -41,16 +40,19 @@ struct cx22702_config
u8 output_mode;
};
-#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) && defined(MODULE))
-extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
- struct i2c_adapter* i2c);
+#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) \
+ && defined(MODULE))
+extern struct dvb_frontend *cx22702_attach(
+ const struct cx22702_config *config,
+ struct i2c_adapter *i2c);
#else
-static inline struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
- struct i2c_adapter* i2c)
+static inline struct dvb_frontend *cx22702_attach(
+ const struct cx22702_config *config,
+ struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_CX22702
+#endif
-#endif // CX22702_H
+#endif
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c
index deb36f469ad..b144b308a4d 100644
--- a/drivers/media/dvb/frontends/cx24116.c
+++ b/drivers/media/dvb/frontends/cx24116.c
@@ -41,10 +41,14 @@
#include "dvb_frontend.h"
#include "cx24116.h"
-static int debug = 0;
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
#define dprintk(args...) \
do { \
- if (debug) printk ("cx24116: " args); \
+ if (debug) \
+ printk(KERN_INFO "cx24116: " args); \
} while (0)
#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
@@ -68,13 +72,20 @@ static int debug = 0;
#define CX24116_REG_UCB8 (0xca)
#define CX24116_REG_CLKDIV (0xf3)
#define CX24116_REG_RATEDIV (0xf9)
-#define CX24116_REG_FECSTATUS (0x9c) /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
+
+/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
+#define CX24116_REG_FECSTATUS (0x9c)
/* FECSTATUS bits */
-#define CX24116_FEC_FECMASK (0x1f) /* mask to determine configured fec (not tuned) or actual fec (tuned) */
-#define CX24116_FEC_DVBS (0x20) /* Select DVB-S demodulator, else DVB-S2 */
+/* mask to determine configured fec (not tuned) or actual fec (tuned) */
+#define CX24116_FEC_FECMASK (0x1f)
+
+/* Select DVB-S demodulator, else DVB-S2 */
+#define CX24116_FEC_DVBS (0x20)
#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */
-#define CX24116_FEC_PILOT (0x80) /* Pilot mode requested when tuning else always reset when tuned */
+
+/* Pilot mode requested when tuning else always reset when tuned */
+#define CX24116_FEC_PILOT (0x80)
/* arg buffer size */
#define CX24116_ARGLEN (0x1e)
@@ -116,12 +127,17 @@ static int debug = 0;
/* DiSEqC tone burst */
static int toneburst = 1;
+module_param(toneburst, int, 0644);
+MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
+ "2=MESSAGE CACHE (default:1)");
/* SNR measurements */
-static int esno_snr = 0;
+static int esno_snr;
+module_param(esno_snr, int, 0644);
+MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, "\
+ "1=ESNO(db * 10) (default:0)");
-enum cmds
-{
+enum cmds {
CMD_SET_VCO = 0x10,
CMD_TUNEREQUEST = 0x11,
CMD_MPEGCONFIG = 0x13,
@@ -138,8 +154,7 @@ enum cmds
};
/* The Demod/Tuner can't easily provide these, we cache them */
-struct cx24116_tuning
-{
+struct cx24116_tuning {
u32 frequency;
u32 symbol_rate;
fe_spectral_inversion_t inversion;
@@ -158,16 +173,14 @@ struct cx24116_tuning
};
/* Basic commands that are sent to the firmware */
-struct cx24116_cmd
-{
+struct cx24116_cmd {
u8 len;
u8 args[CX24116_ARGLEN];
};
-struct cx24116_state
-{
- struct i2c_adapter* i2c;
- const struct cx24116_config* config;
+struct cx24116_state {
+ struct i2c_adapter *i2c;
+ const struct cx24116_config *config;
struct dvb_frontend frontend;
@@ -179,19 +192,20 @@ struct cx24116_state
struct cx24116_cmd dsec_cmd;
};
-static int cx24116_writereg(struct cx24116_state* state, int reg, int data)
+static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
{
u8 buf[] = { reg, data };
struct i2c_msg msg = { .addr = state->config->demod_address,
.flags = 0, .buf = buf, .len = 2 };
int err;
- if (debug>1)
+ if (debug > 1)
printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
- __func__,reg, data);
+ __func__, reg, data);
- if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
- printk("%s: writereg error(err == %i, reg == 0x%02x,"
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1) {
+ printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
" value == 0x%02x)\n", __func__, err, reg, data);
return -EREMOTEIO;
}
@@ -200,7 +214,8 @@ static int cx24116_writereg(struct cx24116_state* state, int reg, int data)
}
/* Bulk byte writes to a single I2C address, for 32k firmware load */
-static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len)
+static int cx24116_writeregN(struct cx24116_state *state, int reg,
+ const u8 *data, u16 len)
{
int ret = -EREMOTEIO;
struct i2c_msg msg;
@@ -221,12 +236,13 @@ static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16
msg.buf = buf;
msg.len = len + 1;
- if (debug>1)
- printk("cx24116: %s: write regN 0x%02x, len = %d\n",
- __func__,reg, len);
+ if (debug > 1)
+ printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n",
+ __func__, reg, len);
- if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
- printk("%s: writereg error(err == %i, reg == 0x%02x\n",
+ ret = i2c_transfer(state->i2c, &msg, 1);
+ if (ret != 1) {
+ printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
__func__, ret, reg);
ret = -EREMOTEIO;
}
@@ -237,30 +253,35 @@ error:
return ret;
}
-static int cx24116_readreg(struct cx24116_state* state, u8 reg)
+static int cx24116_readreg(struct cx24116_state *state, u8 reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
struct i2c_msg msg[] = {
- { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
- { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+ { .addr = state->config->demod_address, .flags = 0,
+ .buf = b0, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD,
+ .buf = b1, .len = 1 }
};
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
- printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
+ printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
+ __func__, reg, ret);
return ret;
}
- if (debug>1)
- printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]);
+ if (debug > 1)
+ printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n",
+ reg, b1[0]);
return b1[0];
}
-static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion)
+static int cx24116_set_inversion(struct cx24116_state *state,
+ fe_spectral_inversion_t inversion)
{
dprintk("%s(%d)\n", __func__, inversion);
@@ -308,10 +329,10 @@ static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_invers
* Eg.(2/3) szap "Zone Horror"
*
* mask/val = 0x04, 0x20
- * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK
+ * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK
*
* mask/val = 0x04, 0x30
- * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK
+ * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK
*
* After tuning FECSTATUS contains actual FEC
* in use numbered 1 through to 8 for 1/2 .. 2/3 etc
@@ -389,18 +410,16 @@ struct cx24116_modfec {
*/
};
-static int cx24116_lookup_fecmod(struct cx24116_state* state,
+static int cx24116_lookup_fecmod(struct cx24116_state *state,
fe_modulation_t m, fe_code_rate_t f)
{
int i, ret = -EOPNOTSUPP;
dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
- for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++)
- {
- if( (m == CX24116_MODFEC_MODES[i].modulation) &&
- (f == CX24116_MODFEC_MODES[i].fec) )
- {
+ for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
+ if ((m == CX24116_MODFEC_MODES[i].modulation) &&
+ (f == CX24116_MODFEC_MODES[i].fec)) {
ret = i;
break;
}
@@ -409,7 +428,8 @@ static int cx24116_lookup_fecmod(struct cx24116_state* state,
return ret;
}
-static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec)
+static int cx24116_set_fec(struct cx24116_state *state,
+ fe_modulation_t mod, fe_code_rate_t fec)
{
int ret = 0;
@@ -417,7 +437,7 @@ static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_
ret = cx24116_lookup_fecmod(state, mod, fec);
- if(ret < 0)
+ if (ret < 0)
return ret;
state->dnxt.fec = fec;
@@ -429,7 +449,7 @@ static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_
return 0;
}
-static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate)
+static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
{
dprintk("%s(%d)\n", __func__, rate);
@@ -446,42 +466,49 @@ static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate)
return 0;
}
-static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw);
+static int cx24116_load_firmware(struct dvb_frontend *fe,
+ const struct firmware *fw);
-static int cx24116_firmware_ondemand(struct dvb_frontend* fe)
+static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
{
struct cx24116_state *state = fe->demodulator_priv;
const struct firmware *fw;
int ret = 0;
- dprintk("%s()\n",__func__);
+ dprintk("%s()\n", __func__);
- if (cx24116_readreg(state, 0x20) > 0)
- {
+ if (cx24116_readreg(state, 0x20) > 0) {
if (state->skip_fw_load)
return 0;
/* Load firmware */
- /* request the firmware, this will block until someone uploads it */
- printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE);
- ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev);
- printk("%s: Waiting for firmware upload(2)...\n", __func__);
+ /* request the firmware, this will block until loaded */
+ printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
+ __func__, CX24116_DEFAULT_FIRMWARE);
+ ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
+ &state->i2c->dev);
+ printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
+ __func__);
if (ret) {
- printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__);
+ printk(KERN_ERR "%s: No firmware uploaded "
+ "(timeout or file not found?)\n", __func__);
return ret;
}
- /* Make sure we don't recurse back through here during loading */
+ /* Make sure we don't recurse back through here
+ * during loading */
state->skip_fw_load = 1;
ret = cx24116_load_firmware(fe, fw);
if (ret)
- printk("%s: Writing firmware to device failed\n", __func__);
+ printk(KERN_ERR "%s: Writing firmware to device failed\n",
+ __func__);
release_firmware(fw);
- printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed");
+ printk(KERN_INFO "%s: Firmware upload %s\n", __func__,
+ ret == 0 ? "complete" : "failed");
/* Ensure firmware is always loaded if required */
state->skip_fw_load = 0;
@@ -490,8 +517,10 @@ static int cx24116_firmware_ondemand(struct dvb_frontend* fe)
return ret;
}
-/* Take a basic firmware command structure, format it and forward it for processing */
-static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd)
+/* Take a basic firmware command structure, format it
+ * and forward it for processing
+ */
+static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
{
struct cx24116_state *state = fe->demodulator_priv;
int i, ret;
@@ -499,49 +528,49 @@ static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd)
dprintk("%s()\n", __func__);
/* Load the firmware if required */
- if ( (ret = cx24116_firmware_ondemand(fe)) != 0)
- {
- printk("%s(): Unable initialise the firmware\n", __func__);
+ ret = cx24116_firmware_ondemand(fe);
+ if (ret != 0) {
+ printk(KERN_ERR "%s(): Unable initialise the firmware\n",
+ __func__);
return ret;
}
/* Write the command */
- for(i = 0; i < cmd->len ; i++)
- {
+ for (i = 0; i < cmd->len ; i++) {
dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
cx24116_writereg(state, i, cmd->args[i]);
}
/* Start execution and wait for cmd to terminate */
cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
- while( cx24116_readreg(state, CX24116_REG_EXECUTE) )
- {
+ while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
msleep(10);
- if(i++ > 64)
- {
- /* Avoid looping forever if the firmware does no respond */
- printk("%s() Firmware not responding\n", __func__);
+ if (i++ > 64) {
+ /* Avoid looping forever if the firmware does
+ not respond */
+ printk(KERN_WARNING "%s() Firmware not responding\n",
+ __func__);
return -EREMOTEIO;
}
}
return 0;
}
-static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+static int cx24116_load_firmware(struct dvb_frontend *fe,
+ const struct firmware *fw)
{
- struct cx24116_state* state = fe->demodulator_priv;
+ struct cx24116_state *state = fe->demodulator_priv;
struct cx24116_cmd cmd;
int i, ret;
unsigned char vers[4];
dprintk("%s\n", __func__);
- dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n"
- ,fw->size
- ,fw->data[0]
- ,fw->data[1]
- ,fw->data[ fw->size-2 ]
- ,fw->data[ fw->size-1 ]
- );
+ dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
+ fw->size,
+ fw->data[0],
+ fw->data[1],
+ fw->data[fw->size-2],
+ fw->data[fw->size-1]);
/* Toggle 88x SRST pin to reset demod */
if (state->config->reset_device)
@@ -587,7 +616,7 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd.args[0x07] = 0x9d;
cmd.args[0x08] = 0xfc;
cmd.args[0x09] = 0x06;
- cmd.len= 0x0a;
+ cmd.len = 0x0a;
ret = cx24116_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
@@ -598,7 +627,7 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd.args[0x00] = CMD_TUNERINIT;
cmd.args[0x01] = 0x00;
cmd.args[0x02] = 0x00;
- cmd.len= 0x03;
+ cmd.len = 0x03;
ret = cx24116_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
@@ -615,36 +644,38 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware
else
cmd.args[0x04] = 0x02;
cmd.args[0x05] = 0x00;
- cmd.len= 0x06;
+ cmd.len = 0x06;
ret = cx24116_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
/* Firmware CMD 35: Get firmware version */
cmd.args[0x00] = CMD_UPDFWVERS;
- cmd.len= 0x02;
- for(i=0; i<4; i++) {
+ cmd.len = 0x02;
+ for (i = 0; i < 4; i++) {
cmd.args[0x01] = i;
ret = cx24116_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
- vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX);
+ vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
}
- printk("%s: FW version %i.%i.%i.%i\n", __func__,
+ printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__,
vers[0], vers[1], vers[2], vers[3]);
return 0;
}
-static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+static int cx24116_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
{
/* The isl6421 module will override this function in the fops. */
- dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__);
+ dprintk("%s() This should never appear if the isl6421 module "
+ "is loaded correctly\n", __func__);
return -EOPNOTSUPP;
}
-static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct cx24116_state *state = fe->demodulator_priv;
@@ -666,22 +697,23 @@ static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status)
return 0;
}
-static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber)
+static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct cx24116_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
- *ber = ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) |
- ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) |
- ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8 ) |
- cx24116_readreg(state, CX24116_REG_BER0 );
+ *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
+ (cx24116_readreg(state, CX24116_REG_BER16) << 16) |
+ (cx24116_readreg(state, CX24116_REG_BER8) << 8) |
+ cx24116_readreg(state, CX24116_REG_BER0);
return 0;
}
/* TODO Determine function and scale appropriately */
-static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+static int cx24116_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
{
struct cx24116_state *state = fe->demodulator_priv;
struct cx24116_cmd cmd;
@@ -692,39 +724,43 @@ static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_str
/* Firmware CMD 19: Get AGC */
cmd.args[0x00] = CMD_GETAGC;
- cmd.len= 0x01;
+ cmd.len = 0x01;
ret = cx24116_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
- sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) |
- ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 );
- *signal_strength= 0 - sig_reading;
+ sig_reading =
+ (cx24116_readreg(state,
+ CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
+ (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
+ *signal_strength = 0 - sig_reading;
- dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength);
+ dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
+ __func__, sig_reading, *signal_strength);
return 0;
}
/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
-static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr)
+static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
{
struct cx24116_state *state = fe->demodulator_priv;
u8 snr_reading;
static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
- 0x00000,0x0199A,0x03333,0x04ccD,0x06667,
- 0x08000,0x0999A,0x0b333,0x0cccD,0x0e667,
- 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 };
+ 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
+ 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
+ 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
+ 0x18000 };
dprintk("%s()\n", __func__);
snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
- if(snr_reading >= 0xa0 /* 100% */)
+ if (snr_reading >= 0xa0 /* 100% */)
*snr = 0xffff;
else
- *snr = snr_tab [ ( snr_reading & 0xf0 ) >> 4 ] +
- ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 );
+ *snr = snr_tab[(snr_reading & 0xf0) >> 4] +
+ (snr_tab[(snr_reading & 0x0f)] >> 4);
dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
snr_reading, *snr);
@@ -736,7 +772,7 @@ static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr)
* ESNO, from 0->30db (values 0->300). We provide this value by
* default.
*/
-static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr)
+static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
{
struct cx24116_state *state = fe->demodulator_priv;
@@ -750,7 +786,7 @@ static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr)
return 0;
}
-static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr)
+static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
{
if (esno_snr == 1)
return cx24116_read_snr_esno(fe, snr);
@@ -758,27 +794,27 @@ static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr)
return cx24116_read_snr_pct(fe, snr);
}
-static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct cx24116_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
- *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) |
+ *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
cx24116_readreg(state, CX24116_REG_UCB0);
return 0;
}
/* Overwrite the current tuning params, we are about to tune */
-static void cx24116_clone_params(struct dvb_frontend* fe)
+static void cx24116_clone_params(struct dvb_frontend *fe)
{
struct cx24116_state *state = fe->demodulator_priv;
memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
}
/* Wait for LNB */
-static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
+static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
{
struct cx24116_state *state = fe->demodulator_priv;
int i;
@@ -787,7 +823,7 @@ static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
cx24116_readreg(state, CX24116_REG_QSTATUS));
/* Wait for up to 300 ms */
- for(i = 0; i < 30 ; i++) {
+ for (i = 0; i < 30 ; i++) {
if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
return 0;
msleep(10);
@@ -798,20 +834,21 @@ static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
return -ETIMEDOUT; /* -EBUSY ? */
}
-static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+static int cx24116_set_tone(struct dvb_frontend *fe,
+ fe_sec_tone_mode_t tone)
{
struct cx24116_cmd cmd;
int ret;
dprintk("%s(%d)\n", __func__, tone);
- if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) {
- printk("%s: Invalid, tone=%d\n", __func__, tone);
+ if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+ printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
return -EINVAL;
}
/* Wait for LNB ready */
ret = cx24116_wait_for_lnb(fe);
- if(ret != 0)
+ if (ret != 0)
return ret;
/* Min delay time after DiSEqC send */
@@ -820,7 +857,7 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
/* This is always done before the tone is set */
cmd.args[0x00] = CMD_SET_TONEPRE;
cmd.args[0x01] = 0x00;
- cmd.len= 0x02;
+ cmd.len = 0x02;
ret = cx24116_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
@@ -836,11 +873,11 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
cmd.args[0x03] = 0x01;
break;
case SEC_TONE_OFF:
- dprintk("%s: setting tone off\n",__func__);
+ dprintk("%s: setting tone off\n", __func__);
cmd.args[0x03] = 0x00;
break;
}
- cmd.len= 0x04;
+ cmd.len = 0x04;
/* Min delay time before DiSEqC send */
msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
@@ -849,7 +886,7 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
}
/* Initialise DiSEqC */
-static int cx24116_diseqc_init(struct dvb_frontend* fe)
+static int cx24116_diseqc_init(struct dvb_frontend *fe)
{
struct cx24116_state *state = fe->demodulator_priv;
struct cx24116_cmd cmd;
@@ -864,7 +901,7 @@ static int cx24116_diseqc_init(struct dvb_frontend* fe)
cmd.args[0x05] = 0x28;
cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
cmd.args[0x07] = 0x01;
- cmd.len= 0x08;
+ cmd.len = 0x08;
ret = cx24116_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
@@ -878,36 +915,38 @@ static int cx24116_diseqc_init(struct dvb_frontend* fe)
/* Unknown */
state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
- state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */
+ /* Continuation flag? */
+ state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
/* DiSEqC message length */
state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
/* Command length */
- state->dsec_cmd.len= CX24116_DISEQC_MSGOFS;
+ state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
return 0;
}
/* Send DiSEqC message with derived burst (hack) || previous burst */
-static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d)
+static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *d)
{
struct cx24116_state *state = fe->demodulator_priv;
int i, ret;
/* Dump DiSEqC message */
if (debug) {
- printk("cx24116: %s(", __func__);
- for(i = 0 ; i < d->msg_len ;) {
- printk("0x%02x", d->msg[i]);
- if(++i < d->msg_len)
- printk(", ");
- }
+ printk(KERN_INFO "cx24116: %s(", __func__);
+ for (i = 0 ; i < d->msg_len ;) {
+ printk(KERN_INFO "0x%02x", d->msg[i]);
+ if (++i < d->msg_len)
+ printk(KERN_INFO ", ");
+ }
printk(") toneburst=%d\n", toneburst);
}
/* Validate length */
- if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
+ if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
return -EINVAL;
/* DiSEqC message */
@@ -918,18 +957,19 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
/* Command length */
- state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
+ state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
+ state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
/* DiSEqC toneburst */
- if(toneburst == CX24116_DISEQC_MESGCACHE)
+ if (toneburst == CX24116_DISEQC_MESGCACHE)
/* Message is cached */
return 0;
- else if(toneburst == CX24116_DISEQC_TONEOFF)
+ else if (toneburst == CX24116_DISEQC_TONEOFF)
/* Message is sent without burst */
state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
- else if(toneburst == CX24116_DISEQC_TONECACHE) {
+ else if (toneburst == CX24116_DISEQC_TONECACHE) {
/*
* Message is sent with derived else cached burst
*
@@ -948,15 +988,17 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
* Y = VOLTAGE (0=13V, 1=18V)
* Z = BAND (0=LOW, 1=HIGH(22K))
*/
- if(d->msg_len >= 4 && d->msg[2] == 0x38)
- state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2);
- if(debug)
- dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]);
+ if (d->msg_len >= 4 && d->msg[2] == 0x38)
+ state->dsec_cmd.args[CX24116_DISEQC_BURST] =
+ ((d->msg[3] & 4) >> 2);
+ if (debug)
+ dprintk("%s burst=%d\n", __func__,
+ state->dsec_cmd.args[CX24116_DISEQC_BURST]);
}
/* Wait for LNB ready */
ret = cx24116_wait_for_lnb(fe);
- if(ret != 0)
+ if (ret != 0)
return ret;
/* Wait for voltage/min repeat delay */
@@ -964,7 +1006,7 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
/* Command */
ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
- if(ret != 0)
+ if (ret != 0)
return ret;
/*
* Wait for send
@@ -976,29 +1018,33 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
* 12.5ms burst +
* >15ms delay (XXX determine if FW does this, see set_tone)
*/
- msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) );
+ msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
+ ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
return 0;
}
/* Send DiSEqC burst */
-static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
+ fe_sec_mini_cmd_t burst)
{
struct cx24116_state *state = fe->demodulator_priv;
int ret;
- dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst);
+ dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
/* DiSEqC burst */
if (burst == SEC_MINI_A)
- state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
- else if(burst == SEC_MINI_B)
- state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B;
+ state->dsec_cmd.args[CX24116_DISEQC_BURST] =
+ CX24116_DISEQC_MINI_A;
+ else if (burst == SEC_MINI_B)
+ state->dsec_cmd.args[CX24116_DISEQC_BURST] =
+ CX24116_DISEQC_MINI_B;
else
return -EINVAL;
/* DiSEqC toneburst */
- if(toneburst != CX24116_DISEQC_MESGCACHE)
+ if (toneburst != CX24116_DISEQC_MESGCACHE)
/* Burst is cached */
return 0;
@@ -1006,7 +1052,7 @@ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
/* Wait for LNB ready */
ret = cx24116_wait_for_lnb(fe);
- if(ret != 0)
+ if (ret != 0)
return ret;
/* Wait for voltage/min repeat delay */
@@ -1014,7 +1060,7 @@ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
/* Command */
ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
- if(ret != 0)
+ if (ret != 0)
return ret;
/*
@@ -1027,34 +1073,32 @@ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
* 12.5ms burst +
* >15ms delay (XXX determine if FW does this, see set_tone)
*/
- msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 );
+ msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
return 0;
}
-static void cx24116_release(struct dvb_frontend* fe)
+static void cx24116_release(struct dvb_frontend *fe)
{
- struct cx24116_state* state = fe->demodulator_priv;
- dprintk("%s\n",__func__);
+ struct cx24116_state *state = fe->demodulator_priv;
+ dprintk("%s\n", __func__);
kfree(state);
}
static struct dvb_frontend_ops cx24116_ops;
-struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
- struct i2c_adapter* i2c)
+struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
+ struct i2c_adapter *i2c)
{
- struct cx24116_state* state = NULL;
+ struct cx24116_state *state = NULL;
int ret;
- dprintk("%s\n",__func__);
+ dprintk("%s\n", __func__);
/* allocate memory for the internal state */
state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
- if (state == NULL) {
- printk("Unable to kmalloc\n");
+ if (state == NULL)
goto error1;
- }
/* setup the state */
memset(state, 0, sizeof(struct cx24116_state));
@@ -1063,32 +1107,36 @@ struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
state->i2c = i2c;
/* check if the demod is present */
- ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE);
+ ret = (cx24116_readreg(state, 0xFF) << 8) |
+ cx24116_readreg(state, 0xFE);
if (ret != 0x0501) {
- printk("Invalid probe, probably not a CX24116 device\n");
+ printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
goto error2;
}
/* create dvb_frontend */
- memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &cx24116_ops,
+ sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
error2: kfree(state);
error1: return NULL;
}
+EXPORT_SYMBOL(cx24116_attach);
+
/*
* Initialise or wake up device
*
* Power config will reset and load initial firmware if required
*/
-static int cx24116_initfe(struct dvb_frontend* fe)
+static int cx24116_initfe(struct dvb_frontend *fe)
{
- struct cx24116_state* state = fe->demodulator_priv;
+ struct cx24116_state *state = fe->demodulator_priv;
struct cx24116_cmd cmd;
int ret;
- dprintk("%s()\n",__func__);
+ dprintk("%s()\n", __func__);
/* Power on */
cx24116_writereg(state, 0xe0, 0);
@@ -1098,9 +1146,9 @@ static int cx24116_initfe(struct dvb_frontend* fe)
/* Firmware CMD 36: Power config */
cmd.args[0x00] = CMD_TUNERSLEEP;
cmd.args[0x01] = 0;
- cmd.len= 0x02;
+ cmd.len = 0x02;
ret = cx24116_cmd_execute(fe, &cmd);
- if(ret != 0)
+ if (ret != 0)
return ret;
return cx24116_diseqc_init(fe);
@@ -1109,20 +1157,20 @@ static int cx24116_initfe(struct dvb_frontend* fe)
/*
* Put device to sleep
*/
-static int cx24116_sleep(struct dvb_frontend* fe)
+static int cx24116_sleep(struct dvb_frontend *fe)
{
- struct cx24116_state* state = fe->demodulator_priv;
+ struct cx24116_state *state = fe->demodulator_priv;
struct cx24116_cmd cmd;
int ret;
- dprintk("%s()\n",__func__);
+ dprintk("%s()\n", __func__);
/* Firmware CMD 36: Power config */
cmd.args[0x00] = CMD_TUNERSLEEP;
cmd.args[0x01] = 1;
- cmd.len= 0x02;
+ cmd.len = 0x02;
ret = cx24116_cmd_execute(fe, &cmd);
- if(ret != 0)
+ if (ret != 0)
return ret;
/* Power off (Shutdown clocks) */
@@ -1133,13 +1181,15 @@ static int cx24116_sleep(struct dvb_frontend* fe)
return 0;
}
-static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp)
+static int cx24116_set_property(struct dvb_frontend *fe,
+ struct dtv_property *tvp)
{
dprintk("%s(..)\n", __func__);
return 0;
}
-static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp)
+static int cx24116_get_property(struct dvb_frontend *fe,
+ struct dtv_property *tvp)
{
dprintk("%s(..)\n", __func__);
return 0;
@@ -1148,7 +1198,8 @@ static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tv
/* dvb-core told us to tune, the tv property cache will be complete,
* it's safe for is to pull values and use them for tuning purposes.
*/
-static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24116_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
struct cx24116_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -1156,96 +1207,102 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
fe_status_t tunerstat;
int i, status, ret, retune;
- dprintk("%s()\n",__func__);
+ dprintk("%s()\n", __func__);
- switch(c->delivery_system) {
- case SYS_DVBS:
- dprintk("%s: DVB-S delivery system selected\n",__func__);
+ switch (c->delivery_system) {
+ case SYS_DVBS:
+ dprintk("%s: DVB-S delivery system selected\n", __func__);
- /* Only QPSK is supported for DVB-S */
- if(c->modulation != QPSK) {
- dprintk("%s: unsupported modulation selected (%d)\n",
- __func__, c->modulation);
- return -EOPNOTSUPP;
- }
+ /* Only QPSK is supported for DVB-S */
+ if (c->modulation != QPSK) {
+ dprintk("%s: unsupported modulation selected (%d)\n",
+ __func__, c->modulation);
+ return -EOPNOTSUPP;
+ }
- /* Pilot doesn't exist in DVB-S, turn bit off */
- state->dnxt.pilot_val = CX24116_PILOT_OFF;
- retune = 1;
+ /* Pilot doesn't exist in DVB-S, turn bit off */
+ state->dnxt.pilot_val = CX24116_PILOT_OFF;
+ retune = 1;
- /* DVB-S only supports 0.35 */
- if(c->rolloff != ROLLOFF_35) {
- dprintk("%s: unsupported rolloff selected (%d)\n",
- __func__, c->rolloff);
- return -EOPNOTSUPP;
- }
- state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
- break;
+ /* DVB-S only supports 0.35 */
+ if (c->rolloff != ROLLOFF_35) {
+ dprintk("%s: unsupported rolloff selected (%d)\n",
+ __func__, c->rolloff);
+ return -EOPNOTSUPP;
+ }
+ state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
+ break;
- case SYS_DVBS2:
- dprintk("%s: DVB-S2 delivery system selected\n",__func__);
-
- /*
- * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
- * but not hardware auto detection
- */
- if(c->modulation != PSK_8 && c->modulation != QPSK) {
- dprintk("%s: unsupported modulation selected (%d)\n",
- __func__, c->modulation);
- return -EOPNOTSUPP;
- }
+ case SYS_DVBS2:
+ dprintk("%s: DVB-S2 delivery system selected\n", __func__);
- switch(c->pilot) {
- case PILOT_AUTO: /* Not supported but emulated */
- retune = 2; /* Fall-through */
- case PILOT_OFF:
- state->dnxt.pilot_val = CX24116_PILOT_OFF;
- break;
- case PILOT_ON:
- state->dnxt.pilot_val = CX24116_PILOT_ON;
- break;
- default:
- dprintk("%s: unsupported pilot mode selected (%d)\n",
- __func__, c->pilot);
- return -EOPNOTSUPP;
- }
+ /*
+ * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
+ * but not hardware auto detection
+ */
+ if (c->modulation != PSK_8 && c->modulation != QPSK) {
+ dprintk("%s: unsupported modulation selected (%d)\n",
+ __func__, c->modulation);
+ return -EOPNOTSUPP;
+ }
- switch(c->rolloff) {
- case ROLLOFF_20:
- state->dnxt.rolloff_val= CX24116_ROLLOFF_020;
- break;
- case ROLLOFF_25:
- state->dnxt.rolloff_val= CX24116_ROLLOFF_025;
- break;
- case ROLLOFF_35:
- state->dnxt.rolloff_val= CX24116_ROLLOFF_035;
- break;
- case ROLLOFF_AUTO: /* Rolloff must be explicit */
- default:
- dprintk("%s: unsupported rolloff selected (%d)\n",
- __func__, c->rolloff);
- return -EOPNOTSUPP;
- }
+ switch (c->pilot) {
+ case PILOT_AUTO: /* Not supported but emulated */
+ state->dnxt.pilot_val = (c->modulation == QPSK)
+ ? CX24116_PILOT_OFF : CX24116_PILOT_ON;
+ retune = 2;
+ break;
+ case PILOT_OFF:
+ state->dnxt.pilot_val = CX24116_PILOT_OFF;
+ break;
+ case PILOT_ON:
+ state->dnxt.pilot_val = CX24116_PILOT_ON;
break;
+ default:
+ dprintk("%s: unsupported pilot mode selected (%d)\n",
+ __func__, c->pilot);
+ return -EOPNOTSUPP;
+ }
+ switch (c->rolloff) {
+ case ROLLOFF_20:
+ state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
+ break;
+ case ROLLOFF_25:
+ state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
+ break;
+ case ROLLOFF_35:
+ state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
+ break;
+ case ROLLOFF_AUTO: /* Rolloff must be explicit */
default:
- dprintk("%s: unsupported delivery system selected (%d)\n",
- __func__, c->delivery_system);
+ dprintk("%s: unsupported rolloff selected (%d)\n",
+ __func__, c->rolloff);
return -EOPNOTSUPP;
+ }
+ break;
+
+ default:
+ dprintk("%s: unsupported delivery system selected (%d)\n",
+ __func__, c->delivery_system);
+ return -EOPNOTSUPP;
}
state->dnxt.modulation = c->modulation;
state->dnxt.frequency = c->frequency;
state->dnxt.pilot = c->pilot;
state->dnxt.rolloff = c->rolloff;
- if ((ret = cx24116_set_inversion(state, c->inversion)) != 0)
+ ret = cx24116_set_inversion(state, c->inversion);
+ if (ret != 0)
return ret;
/* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
- if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0)
+ ret = cx24116_set_fec(state, c->modulation, c->fec_inner);
+ if (ret != 0)
return ret;
- if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) != 0)
+ ret = cx24116_set_symbolrate(state, c->symbol_rate);
+ if (ret != 0)
return ret;
/* discard the 'current' tuning parameters and prepare to tune */
@@ -1271,7 +1328,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
/* Set/Reset B/W */
cmd.args[0x00] = CMD_BANDWIDTH;
cmd.args[0x01] = 0x01;
- cmd.len= 0x02;
+ cmd.len = 0x02;
ret = cx24116_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
@@ -1319,7 +1376,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
}
- cmd.len= 0x13;
+ cmd.len = 0x13;
/* We need to support pilot and non-pilot tuning in the
* driver automatically. This is a workaround for because
@@ -1327,12 +1384,13 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
*/
do {
/* Reset status register */
- status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK;
+ status = cx24116_readreg(state, CX24116_REG_SSTATUS)
+ & CX24116_SIGNAL_MASK;
cx24116_writereg(state, CX24116_REG_SSTATUS, status);
/* Tune */
ret = cx24116_cmd_execute(fe, &cmd);
- if( ret != 0 )
+ if (ret != 0)
break;
/*
@@ -1341,28 +1399,27 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
* If we are able to tune then generally it occurs within 100ms.
* If it takes longer, try a different toneburst setting.
*/
- for(i = 0; i < 50 ; i++) {
+ for (i = 0; i < 50 ; i++) {
cx24116_read_status(fe, &tunerstat);
status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
- if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
- dprintk("%s: Tuned\n",__func__);
+ if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
+ dprintk("%s: Tuned\n", __func__);
goto tuned;
}
msleep(10);
}
- dprintk("%s: Not tuned\n",__func__);
+ dprintk("%s: Not tuned\n", __func__);
/* Toggle pilot bit when in auto-pilot */
- if(state->dcur.pilot == PILOT_AUTO)
+ if (state->dcur.pilot == PILOT_AUTO)
cmd.args[0x07] ^= CX24116_PILOT_ON;
- }
- while(--retune);
+ } while (--retune);
tuned: /* Set/Reset B/W */
cmd.args[0x00] = CMD_BANDWIDTH;
cmd.args[0x01] = 0x00;
- cmd.len= 0x02;
+ cmd.len = 0x02;
ret = cx24116_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
@@ -1407,17 +1464,7 @@ static struct dvb_frontend_ops cx24116_ops = {
.set_frontend = cx24116_set_frontend,
};
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-module_param(toneburst, int, 0644);
-MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)");
-
-module_param(esno_snr, int, 0644);
-MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)");
-
MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(cx24116_attach);
diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb/frontends/cx24116.h
index 8dbcec26839..4cb3ddd6c62 100644
--- a/drivers/media/dvb/frontends/cx24116.h
+++ b/drivers/media/dvb/frontends/cx24116.h
@@ -23,31 +23,32 @@
#include <linux/dvb/frontend.h>
-struct cx24116_config
-{
+struct cx24116_config {
/* the demodulator's i2c address */
u8 demod_address;
/* Need to set device param for start_dma */
- int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+ int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
/* Need to reset device during firmware loading */
- int (*reset_device)(struct dvb_frontend* fe);
+ int (*reset_device)(struct dvb_frontend *fe);
/* Need to set MPEG parameters */
u8 mpg_clk_pos_pol:0x02;
};
#if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE)
-extern struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
- struct i2c_adapter* i2c);
+extern struct dvb_frontend *cx24116_attach(
+ const struct cx24116_config *config,
+ struct i2c_adapter *i2c);
#else
-static inline struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
- struct i2c_adapter* i2c)
+static inline struct dvb_frontend *cx24116_attach(
+ const struct cx24116_config *config,
+ struct i2c_adapter *i2c)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_CX24116
+#endif
#endif /* CX24116_H */
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 7156157cb34..1a8c36f7606 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -33,7 +33,13 @@
#define XTAL 10111000
static int force_band;
+module_param(force_band, int, 0644);
+MODULE_PARM_DESC(force_band, "Force a specific band select "\
+ "(1-9, default:off).");
+
static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
#define info(args...) do { printk(KERN_INFO "CX24123: " args); } while (0)
#define err(args...) do { printk(KERN_ERR "CX24123: " args); } while (0)
@@ -46,10 +52,9 @@ static int debug;
} \
} while (0)
-struct cx24123_state
-{
- struct i2c_adapter* i2c;
- const struct cx24123_config* config;
+struct cx24123_state {
+ struct i2c_adapter *i2c;
+ const struct cx24123_config *config;
struct dvb_frontend frontend;
@@ -70,8 +75,7 @@ struct cx24123_state
};
/* Various tuner defaults need to be established for a given symbol rate Sps */
-static struct
-{
+static struct cx24123_AGC_val {
u32 symbolrate_low;
u32 symbolrate_high;
u32 VCAprogdata;
@@ -109,8 +113,7 @@ static struct
* fixme: The bounds on the bands do not match the doc in real life.
* fixme: Some of them have been moved, other might need adjustment.
*/
-static struct
-{
+static struct cx24123_bandselect_val {
u32 freq_low;
u32 freq_high;
u32 VCOdivider;
@@ -249,7 +252,8 @@ static int cx24123_i2c_writereg(struct cx24123_state *state,
/* printk(KERN_DEBUG "wr(%02x): %02x %02x\n", i2c_addr, reg, data); */
- if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1) {
printk("%s: writereg error(err == %i, reg == 0x%02x,"
" data == 0x%02x)\n", __func__, err, reg, data);
return err;
@@ -284,7 +288,8 @@ static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg)
#define cx24123_writereg(state, reg, val) \
cx24123_i2c_writereg(state, state->config->demod_address, reg, val)
-static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
+static int cx24123_set_inversion(struct cx24123_state *state,
+ fe_spectral_inversion_t inversion)
{
u8 nom_reg = cx24123_readreg(state, 0x0e);
u8 auto_reg = cx24123_readreg(state, 0x10);
@@ -311,7 +316,8 @@ static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_invers
return 0;
}
-static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion)
+static int cx24123_get_inversion(struct cx24123_state *state,
+ fe_spectral_inversion_t *inversion)
{
u8 val;
@@ -328,18 +334,20 @@ static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_invers
return 0;
}
-static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
+static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec)
{
u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07;
- if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
+ if ((fec < FEC_NONE) || (fec > FEC_AUTO))
fec = FEC_AUTO;
/* Set the soft decision threshold */
- if(fec == FEC_1_2)
- cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) | 0x01);
+ if (fec == FEC_1_2)
+ cx24123_writereg(state, 0x43,
+ cx24123_readreg(state, 0x43) | 0x01);
else
- cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) & ~0x01);
+ cx24123_writereg(state, 0x43,
+ cx24123_readreg(state, 0x43) & ~0x01);
switch (fec) {
case FEC_1_2:
@@ -388,11 +396,11 @@ static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
return 0;
}
-static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec)
+static int cx24123_get_fec(struct cx24123_state *state, fe_code_rate_t *fec)
{
int ret;
- ret = cx24123_readreg (state, 0x1b);
+ ret = cx24123_readreg(state, 0x1b);
if (ret < 0)
return ret;
ret = ret & 0x07;
@@ -433,16 +441,16 @@ static u32 cx24123_int_log2(u32 a, u32 b)
{
u32 exp, nearest = 0;
u32 div = a / b;
- if(a % b >= b / 2) ++div;
- if(div < (1 << 31))
- {
- for(exp = 1; div > exp; nearest++)
+ if (a % b >= b / 2)
+ ++div;
+ if (div < (1 << 31)) {
+ for (exp = 1; div > exp; nearest++)
exp += exp;
}
return nearest;
}
-static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
+static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
{
u32 tmp, sample_rate, ratio, sample_gain;
u8 pll_mult;
@@ -498,9 +506,9 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
cx24123_writereg(state, 0x01, pll_mult * 6);
- cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f );
- cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff );
- cx24123_writereg(state, 0x0a, (ratio ) & 0xff );
+ cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f);
+ cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff);
+ cx24123_writereg(state, 0x0a, ratio & 0xff);
/* also set the demodulator sample gain */
sample_gain = cx24123_int_log2(sample_rate, srate);
@@ -514,10 +522,12 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
}
/*
- * Based on the required frequency and symbolrate, the tuner AGC has to be configured
- * and the correct band selected. Calculate those values
+ * Based on the required frequency and symbolrate, the tuner AGC has
+ * to be configured and the correct band selected.
+ * Calculate those values.
*/
-static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24123_pll_calculate(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
struct cx24123_state *state = fe->demodulator_priv;
u32 ndiv = 0, adiv = 0, vco_div = 0;
@@ -525,6 +535,8 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
int pump = 2;
int band = 0;
int num_bands = ARRAY_SIZE(cx24123_bandselect_vals);
+ struct cx24123_bandselect_val *bsv = NULL;
+ struct cx24123_AGC_val *agcv = NULL;
/* Defaults for low freq, low rate */
state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
@@ -532,58 +544,65 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
state->bandselectarg = cx24123_bandselect_vals[0].progdata;
vco_div = cx24123_bandselect_vals[0].VCOdivider;
- /* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */
- for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++)
- {
- if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
- (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
- state->VCAarg = cx24123_AGC_vals[i].VCAprogdata;
- state->VGAarg = cx24123_AGC_vals[i].VGAprogdata;
- state->FILTune = cx24123_AGC_vals[i].FILTune;
+ /* For the given symbol rate, determine the VCA, VGA and
+ * FILTUNE programming bits */
+ for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) {
+ agcv = &cx24123_AGC_vals[i];
+ if ((agcv->symbolrate_low <= p->u.qpsk.symbol_rate) &&
+ (agcv->symbolrate_high >= p->u.qpsk.symbol_rate)) {
+ state->VCAarg = agcv->VCAprogdata;
+ state->VGAarg = agcv->VGAprogdata;
+ state->FILTune = agcv->FILTune;
}
}
/* determine the band to use */
- if(force_band < 1 || force_band > num_bands)
- {
- for (i = 0; i < num_bands; i++)
- {
- if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) &&
- (cx24123_bandselect_vals[i].freq_high >= p->frequency) )
+ if (force_band < 1 || force_band > num_bands) {
+ for (i = 0; i < num_bands; i++) {
+ bsv = &cx24123_bandselect_vals[i];
+ if ((bsv->freq_low <= p->frequency) &&
+ (bsv->freq_high >= p->frequency))
band = i;
}
- }
- else
+ } else
band = force_band - 1;
state->bandselectarg = cx24123_bandselect_vals[band].progdata;
vco_div = cx24123_bandselect_vals[band].VCOdivider;
/* determine the charge pump current */
- if ( p->frequency < (cx24123_bandselect_vals[band].freq_low + cx24123_bandselect_vals[band].freq_high)/2 )
+ if (p->frequency < (cx24123_bandselect_vals[band].freq_low +
+ cx24123_bandselect_vals[band].freq_high) / 2)
pump = 0x01;
else
pump = 0x02;
/* Determine the N/A dividers for the requested lband freq (in kHz). */
- /* Note: the reference divider R=10, frequency is in KHz, XTAL is in Hz */
- ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff;
- adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f;
+ /* Note: the reference divider R=10, frequency is in KHz,
+ * XTAL is in Hz */
+ ndiv = (((p->frequency * vco_div * 10) /
+ (2 * XTAL / 1000)) / 32) & 0x1ff;
+ adiv = (((p->frequency * vco_div * 10) /
+ (2 * XTAL / 1000)) % 32) & 0x1f;
if (adiv == 0 && ndiv > 0)
ndiv--;
- /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */
- state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv;
+ /* control bits 11, refdiv 11, charge pump polarity 1,
+ * charge pump current, ndiv, adiv */
+ state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) |
+ (pump << 14) | (ndiv << 5) | adiv;
return 0;
}
/*
* Tuner data is 21 bits long, must be left-aligned in data.
- * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip.
+ * Tuner cx24109 is written through a dedicated 3wire interface
+ * on the demod chip.
*/
-static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data)
+static int cx24123_pll_writereg(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p, u32 data)
{
struct cx24123_state *state = fe->demodulator_priv;
unsigned long timeout;
@@ -610,7 +629,7 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
/* send another 8 bytes, wait for the send to be completed */
timeout = jiffies + msecs_to_jiffies(40);
- cx24123_writereg(state, 0x22, (data>>8) & 0xff );
+ cx24123_writereg(state, 0x22, (data >> 8) & 0xff);
while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
if (time_after(jiffies, timeout)) {
err("%s: demodulator is not responding, "\
@@ -620,9 +639,10 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
msleep(10);
}
- /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */
+ /* send the lower 5 bits of this byte, padded with 3 LBB,
+ * wait for the send to be completed */
timeout = jiffies + msecs_to_jiffies(40);
- cx24123_writereg(state, 0x22, (data) & 0xff );
+ cx24123_writereg(state, 0x22, (data) & 0xff);
while ((cx24123_readreg(state, 0x20) & 0x80)) {
if (time_after(jiffies, timeout)) {
err("%s: demodulator is not responding," \
@@ -639,7 +659,8 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
return 0;
}
-static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24123_pll_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
@@ -690,7 +711,7 @@ static int cx24123_repeater_mode(struct cx24123_state *state, u8 mode, u8 start)
return cx24123_writereg(state, 0x23, r);
}
-static int cx24123_initfe(struct dvb_frontend* fe)
+static int cx24123_initfe(struct dvb_frontend *fe)
{
struct cx24123_state *state = fe->demodulator_priv;
int i;
@@ -699,19 +720,22 @@ static int cx24123_initfe(struct dvb_frontend* fe)
/* Configure the demod to a good set of defaults */
for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
- cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
+ cx24123_writereg(state, cx24123_regdata[i].reg,
+ cx24123_regdata[i].data);
/* Set the LNB polarity */
- if(state->config->lnb_polarity)
- cx24123_writereg(state, 0x32, cx24123_readreg(state, 0x32) | 0x02);
+ if (state->config->lnb_polarity)
+ cx24123_writereg(state, 0x32,
+ cx24123_readreg(state, 0x32) | 0x02);
if (state->config->dont_use_pll)
- cx24123_repeater_mode(state, 1, 0);
+ cx24123_repeater_mode(state, 1, 0);
return 0;
}
-static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+static int cx24123_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
{
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
@@ -740,7 +764,7 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
{
unsigned long timeout = jiffies + msecs_to_jiffies(200);
while (!(cx24123_readreg(state, 0x29) & 0x40)) {
- if(time_after(jiffies, timeout)) {
+ if (time_after(jiffies, timeout)) {
err("%s: diseqc queue not ready, " \
"command may be lost.\n", __func__);
break;
@@ -749,7 +773,8 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
}
}
-static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
+static int cx24123_send_diseqc_msg(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *cmd)
{
struct cx24123_state *state = fe->demodulator_priv;
int i, val, tone;
@@ -771,20 +796,21 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
val = cx24123_readreg(state, 0x29);
- cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
+ cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) |
+ ((cmd->msg_len-3) & 3));
/* wait for diseqc message to finish sending */
cx24123_wait_for_diseqc(state);
/* restart continuous tone if enabled */
- if (tone & 0x10) {
+ if (tone & 0x10)
cx24123_writereg(state, 0x29, tone & ~0x40);
- }
return 0;
}
-static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+static int cx24123_diseqc_send_burst(struct dvb_frontend *fe,
+ fe_sec_mini_cmd_t burst)
{
struct cx24123_state *state = fe->demodulator_priv;
int val, tone;
@@ -814,13 +840,13 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
/* restart continuous tone if enabled */
- if (tone & 0x10) {
+ if (tone & 0x10)
cx24123_writereg(state, 0x29, tone & ~0x40);
- }
+
return 0;
}
-static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int cx24123_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct cx24123_state *state = fe->demodulator_priv;
int sync = cx24123_readreg(state, 0x14);
@@ -853,8 +879,9 @@ static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
}
/*
- * Configured to return the measurement of errors in blocks, because no UCBLOCKS value
- * is available, so this value doubles up to satisfy both measurements
+ * Configured to return the measurement of errors in blocks,
+ * because no UCBLOCKS value is available, so this value doubles up
+ * to satisfy both measurements.
*/
static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber)
{
@@ -876,7 +903,8 @@ static int cx24123_read_signal_strength(struct dvb_frontend *fe,
{
struct cx24123_state *state = fe->demodulator_priv;
- *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
+ /* larger = better */
+ *signal_strength = cx24123_readreg(state, 0x3b) << 8;
dprintk("Signal strength = %d\n", *signal_strength);
@@ -907,7 +935,7 @@ static int cx24123_set_frontend(struct dvb_frontend *fe,
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
- state->currentfreq=p->frequency;
+ state->currentfreq = p->frequency;
state->currentsymbolrate = p->u.qpsk.symbol_rate;
cx24123_set_inversion(state, p->inversion);
@@ -932,7 +960,8 @@ static int cx24123_set_frontend(struct dvb_frontend *fe,
return 0;
}
-static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24123_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
struct cx24123_state *state = fe->demodulator_priv;
@@ -952,7 +981,7 @@ static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
return 0;
}
-static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
{
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
@@ -977,8 +1006,8 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
return 0;
}
-static int cx24123_tune(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params,
+static int cx24123_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status)
@@ -997,12 +1026,12 @@ static int cx24123_tune(struct dvb_frontend* fe,
static int cx24123_get_algo(struct dvb_frontend *fe)
{
- return 1; //FE_ALGO_HW
+ return 1; /* FE_ALGO_HW */
}
-static void cx24123_release(struct dvb_frontend* fe)
+static void cx24123_release(struct dvb_frontend *fe)
{
- struct cx24123_state* state = fe->demodulator_priv;
+ struct cx24123_state *state = fe->demodulator_priv;
dprintk("\n");
i2c_del_adapter(&state->tuner_i2c_adapter);
kfree(state);
@@ -1013,7 +1042,7 @@ static int cx24123_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap,
{
struct cx24123_state *state = i2c_get_adapdata(i2c_adap);
/* this repeater closes after the first stop */
- cx24123_repeater_mode(state, 1, 1);
+ cx24123_repeater_mode(state, 1, 1);
return i2c_transfer(state->i2c, msg, num);
}
@@ -1037,8 +1066,8 @@ EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter);
static struct dvb_frontend_ops cx24123_ops;
-struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
- struct i2c_adapter* i2c)
+struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
+ struct i2c_adapter *i2c)
{
struct cx24123_state *state =
kzalloc(sizeof(struct cx24123_state), GFP_KERNEL);
@@ -1057,20 +1086,25 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
/* check if the demod is there */
state->demod_rev = cx24123_readreg(state, 0x00);
switch (state->demod_rev) {
- case 0xe1: info("detected CX24123C\n"); break;
- case 0xd1: info("detected CX24123\n"); break;
+ case 0xe1:
+ info("detected CX24123C\n");
+ break;
+ case 0xd1:
+ info("detected CX24123\n");
+ break;
default:
err("wrong demod revision: %x\n", state->demod_rev);
goto error;
}
/* create dvb_frontend */
- memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &cx24123_ops,
+ sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
- /* create tuner i2c adapter */
- if (config->dont_use_pll)
- cx24123_repeater_mode(state, 1, 0);
+ /* create tuner i2c adapter */
+ if (config->dont_use_pll)
+ cx24123_repeater_mode(state, 1, 0);
strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
sizeof(state->tuner_i2c_adapter.name));
@@ -1079,7 +1113,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
state->tuner_i2c_adapter.algo_data = NULL;
i2c_set_adapdata(&state->tuner_i2c_adapter, state);
if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
- err("tuner i2c bus could not be initialized\n");
+ err("tuner i2c bus could not be initialized\n");
goto error;
}
@@ -1090,6 +1124,7 @@ error:
return NULL;
}
+EXPORT_SYMBOL(cx24123_attach);
static struct dvb_frontend_ops cx24123_ops = {
@@ -1126,15 +1161,8 @@ static struct dvb_frontend_ops cx24123_ops = {
.get_frontend_algo = cx24123_get_algo,
};
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-module_param(force_band, int, 0644);
-MODULE_PARM_DESC(force_band, "Force a specific band select (1-9, default:off).");
-
MODULE_DESCRIPTION("DVB Frontend module for Conexant " \
"CX24123/CX24109/CX24113 hardware");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(cx24123_attach);
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index cc6b411d6d2..51ae866e9fe 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -23,13 +23,12 @@
#include <linux/dvb/frontend.h>
-struct cx24123_config
-{
+struct cx24123_config {
/* the demodulator's i2c address */
u8 demod_address;
/* Need to set device param for start_dma */
- int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+ int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
/* 0 = LNB voltage normal, 1 = LNB voltage inverted */
int lnb_polarity;
@@ -39,7 +38,8 @@ struct cx24123_config
void (*agc_callback) (struct dvb_frontend *);
};
-#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) && defined(MODULE))
+#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) \
+ && defined(MODULE))
extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *);
@@ -56,6 +56,6 @@ static struct i2c_adapter *
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_CX24123
+#endif
#endif /* CX24123_H */
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index 7500a1c53e6..cf4d8936bb8 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -30,10 +30,10 @@
struct s5h1409_state {
- struct i2c_adapter* i2c;
+ struct i2c_adapter *i2c;
/* configuration settings */
- const struct s5h1409_config* config;
+ const struct s5h1409_config *config;
struct dvb_frontend frontend;
@@ -48,6 +48,9 @@ struct s5h1409_state {
};
static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
#define dprintk if (debug) printk
/* Register values to initialise the demod, this will set VSB by default */
@@ -299,10 +302,10 @@ static struct qam256_snr_tab {
};
/* 8 bit registers, 16 bit values */
-static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data)
+static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data)
{
int ret;
- u8 buf [] = { reg, data >> 8, data & 0xff };
+ u8 buf[] = { reg, data >> 8, data & 0xff };
struct i2c_msg msg = { .addr = state->config->demod_address,
.flags = 0, .buf = buf, .len = 3 };
@@ -310,19 +313,19 @@ static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data)
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
- printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+ printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, "
"ret == %i)\n", __func__, reg, data, ret);
return (ret != 1) ? -1 : 0;
}
-static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg)
+static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg)
{
int ret;
- u8 b0 [] = { reg };
- u8 b1 [] = { 0, 0 };
+ u8 b0[] = { reg };
+ u8 b1[] = { 0, 0 };
- struct i2c_msg msg [] = {
+ struct i2c_msg msg[] = {
{ .addr = state->config->demod_address, .flags = 0,
.buf = b0, .len = 1 },
{ .addr = state->config->demod_address, .flags = I2C_M_RD,
@@ -335,9 +338,9 @@ static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg)
return (b1[0] << 8) | b1[1];
}
-static int s5h1409_softreset(struct dvb_frontend* fe)
+static int s5h1409_softreset(struct dvb_frontend *fe)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
@@ -349,11 +352,11 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
}
#define S5H1409_VSB_IF_FREQ 5380
-#define S5H1409_QAM_IF_FREQ state->config->qam_if
+#define S5H1409_QAM_IF_FREQ (state->config->qam_if)
-static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
+static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d KHz)\n", __func__, KHz);
@@ -376,26 +379,26 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
return 0;
}
-static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
+static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, inverted);
- if(inverted == 1)
+ if (inverted == 1)
return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
else
return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
}
-static int s5h1409_enable_modulation(struct dvb_frontend* fe,
+static int s5h1409_enable_modulation(struct dvb_frontend *fe,
fe_modulation_t m)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(0x%08x)\n", __func__, m);
- switch(m) {
+ switch (m) {
case VSB_8:
dprintk("%s() VSB_8\n", __func__);
if (state->if_freq != S5H1409_VSB_IF_FREQ)
@@ -422,9 +425,9 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
return 0;
}
-static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, enable);
@@ -434,9 +437,9 @@ static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
return s5h1409_writereg(state, 0xf3, 0);
}
-static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
+static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, enable);
@@ -448,18 +451,18 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
s5h1409_readreg(state, 0xe3) & 0xfeff);
}
-static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
+static int s5h1409_sleep(struct dvb_frontend *fe, int enable)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, enable);
return s5h1409_writereg(state, 0xf2, enable);
}
-static int s5h1409_register_reset(struct dvb_frontend* fe)
+static int s5h1409_register_reset(struct dvb_frontend *fe)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
@@ -483,7 +486,7 @@ static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
reg &= 0xff;
s5h1409_writereg(state, 0x96, 0x00c);
- if ((reg < 0x38) || (reg > 0x68) ) {
+ if ((reg < 0x38) || (reg > 0x68)) {
s5h1409_writereg(state, 0x93, 0x3332);
s5h1409_writereg(state, 0x9e, 0x2c37);
} else {
@@ -514,7 +517,7 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
s5h1409_writereg(state, 0x96, 0x20);
s5h1409_writereg(state, 0xad,
- ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
+ (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
s5h1409_writereg(state, 0xab,
s5h1409_readreg(state, 0xab) & 0xeffe);
}
@@ -529,10 +532,10 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1409_set_frontend (struct dvb_frontend* fe,
+static int s5h1409_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(frequency=%d)\n", __func__, p->frequency);
@@ -546,9 +549,11 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
msleep(100);
if (fe->ops.tuner_ops.set_params) {
- if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
fe->ops.tuner_ops.set_params(fe, p);
- if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
}
/* Optimize the demod for QAM */
@@ -592,17 +597,17 @@ static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
/* Reset the demod hardware and reset all of the configuration registers
to a default state. */
-static int s5h1409_init (struct dvb_frontend* fe)
+static int s5h1409_init(struct dvb_frontend *fe)
{
int i;
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
s5h1409_sleep(fe, 0);
s5h1409_register_reset(fe);
- for (i=0; i < ARRAY_SIZE(init_tab); i++)
+ for (i = 0; i < ARRAY_SIZE(init_tab); i++)
s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
/* The datasheet says that after initialisation, VSB is default */
@@ -627,9 +632,9 @@ static int s5h1409_init (struct dvb_frontend* fe)
return 0;
}
-static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
u16 reg;
u32 tuner_status = 0;
@@ -637,12 +642,12 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
/* Get the demodulator status */
reg = s5h1409_readreg(state, 0xf1);
- if(reg & 0x1000)
+ if (reg & 0x1000)
*status |= FE_HAS_VITERBI;
- if(reg & 0x8000)
+ if (reg & 0x8000)
*status |= FE_HAS_LOCK | FE_HAS_SYNC;
- switch(state->config->status_mode) {
+ switch (state->config->status_mode) {
case S5H1409_DEMODLOCKING:
if (*status & FE_HAS_VITERBI)
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
@@ -668,12 +673,12 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
return 0;
}
-static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
{
int i, ret = -EINVAL;
dprintk("%s()\n", __func__);
- for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+ for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
if (v < qam256_snr_tab[i].val) {
*snr = qam256_snr_tab[i].data;
ret = 0;
@@ -683,12 +688,12 @@ static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
return ret;
}
-static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
{
int i, ret = -EINVAL;
dprintk("%s()\n", __func__);
- for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+ for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
if (v < qam64_snr_tab[i].val) {
*snr = qam64_snr_tab[i].data;
ret = 0;
@@ -698,12 +703,12 @@ static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
return ret;
}
-static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
{
int i, ret = -EINVAL;
dprintk("%s()\n", __func__);
- for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+ for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
if (v > vsb_snr_tab[i].val) {
*snr = vsb_snr_tab[i].data;
ret = 0;
@@ -714,13 +719,13 @@ static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
return ret;
}
-static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
+static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
u16 reg;
dprintk("%s()\n", __func__);
- switch(state->current_modulation) {
+ switch (state->current_modulation) {
case QAM_64:
reg = s5h1409_readreg(state, 0xf0) & 0xff;
return s5h1409_qam64_lookup_snr(fe, snr, reg);
@@ -737,30 +742,30 @@ static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
return -EINVAL;
}
-static int s5h1409_read_signal_strength(struct dvb_frontend* fe,
- u16* signal_strength)
+static int s5h1409_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
{
return s5h1409_read_snr(fe, signal_strength);
}
-static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
*ucblocks = s5h1409_readreg(state, 0xb5);
return 0;
}
-static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber)
+static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
{
return s5h1409_read_ucblocks(fe, ber);
}
-static int s5h1409_get_frontend(struct dvb_frontend* fe,
+static int s5h1409_get_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
p->frequency = state->current_frequency;
p->u.vsb.modulation = state->current_modulation;
@@ -768,25 +773,25 @@ static int s5h1409_get_frontend(struct dvb_frontend* fe,
return 0;
}
-static int s5h1409_get_tune_settings(struct dvb_frontend* fe,
+static int s5h1409_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1000;
return 0;
}
-static void s5h1409_release(struct dvb_frontend* fe)
+static void s5h1409_release(struct dvb_frontend *fe)
{
- struct s5h1409_state* state = fe->demodulator_priv;
+ struct s5h1409_state *state = fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops s5h1409_ops;
-struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
- struct i2c_adapter* i2c)
+struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
+ struct i2c_adapter *i2c)
{
- struct s5h1409_state* state = NULL;
+ struct s5h1409_state *state = NULL;
u16 reg;
/* allocate memory for the internal state */
@@ -825,6 +830,7 @@ error:
kfree(state);
return NULL;
}
+EXPORT_SYMBOL(s5h1409_attach);
static struct dvb_frontend_ops s5h1409_ops = {
@@ -850,14 +856,10 @@ static struct dvb_frontend_ops s5h1409_ops = {
.release = s5h1409_release,
};
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(s5h1409_attach);
/*
* Local variables:
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
index d1a1d2eb8e1..070d9743e33 100644
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -24,8 +24,7 @@
#include <linux/dvb/frontend.h>
-struct s5h1409_config
-{
+struct s5h1409_config {
/* the demodulator's i2c address */
u8 demod_address;
@@ -60,12 +59,14 @@ struct s5h1409_config
u16 mpeg_timing;
};
-#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
-extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
- struct i2c_adapter* i2c);
+#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \
+ && defined(MODULE))
+extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
+ struct i2c_adapter *i2c);
#else
-static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
- struct i2c_adapter* i2c)
+static inline struct dvb_frontend *s5h1409_attach(
+ const struct s5h1409_config *config,
+ struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
index 2da1a3763de..40644aacffc 100644
--- a/drivers/media/dvb/frontends/s5h1411.c
+++ b/drivers/media/dvb/frontends/s5h1411.c
@@ -38,6 +38,7 @@ struct s5h1411_state {
struct dvb_frontend frontend;
fe_modulation_t current_modulation;
+ unsigned int first_tune:1;
u32 current_frequency;
int if_freq;
@@ -62,7 +63,7 @@ static struct init_tab {
{ S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, },
{ S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, },
{ S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, },
- { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342a, },
+ { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342c, },
{ S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, },
{ S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, },
{ S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, },
@@ -100,7 +101,6 @@ static struct init_tab {
{ S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, },
{ S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, },
{ S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, },
- { S5H1411_I2C_TOP_ADDR, 0xb5, 0xafbb, },
{ S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, },
{ S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, },
{ S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, },
@@ -343,7 +343,7 @@ static int s5h1411_writereg(struct s5h1411_state *state,
u8 addr, u8 reg, u16 data)
{
int ret;
- u8 buf [] = { reg, data >> 8, data & 0xff };
+ u8 buf[] = { reg, data >> 8, data & 0xff };
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
@@ -359,10 +359,10 @@ static int s5h1411_writereg(struct s5h1411_state *state,
static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg)
{
int ret;
- u8 b0 [] = { reg };
- u8 b1 [] = { 0, 0 };
+ u8 b0[] = { reg };
+ u8 b1[] = { 0, 0 };
- struct i2c_msg msg [] = {
+ struct i2c_msg msg[] = {
{ .addr = addr, .flags = 0, .buf = b0, .len = 1 },
{ .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
@@ -393,7 +393,7 @@ static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz)
switch (KHz) {
case 3250:
- s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d9);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d5);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342);
s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9);
break;
@@ -464,13 +464,25 @@ static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion)
if (inversion == 1)
val |= 0x1000; /* Inverted */
- else
- val |= 0x0000;
state->inversion = inversion;
return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val);
}
+static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+ u16 val;
+
+ dprintk("%s(%d)\n", __func__, serial);
+ val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100;
+
+ if (serial == 1)
+ val |= 0x100;
+
+ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val);
+}
+
static int s5h1411_enable_modulation(struct dvb_frontend *fe,
fe_modulation_t m)
{
@@ -478,6 +490,12 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe,
dprintk("%s(0x%08x)\n", __func__, m);
+ if ((state->first_tune == 0) && (m == state->current_modulation)) {
+ dprintk("%s() Already at desired modulation. Skipping...\n",
+ __func__);
+ return 0;
+ }
+
switch (m) {
case VSB_8:
dprintk("%s() VSB_8\n", __func__);
@@ -502,6 +520,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe,
}
state->current_modulation = m;
+ state->first_tune = 0;
s5h1411_softreset(fe);
return 0;
@@ -535,7 +554,7 @@ static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable)
return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val);
}
-static int s5h1411_sleep(struct dvb_frontend *fe, int enable)
+static int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable)
{
struct s5h1411_state *state = fe->demodulator_priv;
@@ -551,6 +570,11 @@ static int s5h1411_sleep(struct dvb_frontend *fe, int enable)
return 0;
}
+static int s5h1411_sleep(struct dvb_frontend *fe)
+{
+ return s5h1411_set_powerstate(fe, 1);
+}
+
static int s5h1411_register_reset(struct dvb_frontend *fe)
{
struct s5h1411_state *state = fe->demodulator_priv;
@@ -574,9 +598,6 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe,
s5h1411_enable_modulation(fe, p->u.vsb.modulation);
- /* Allow the demod to settle */
- msleep(100);
-
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -587,6 +608,10 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 0);
}
+ /* Issue a reset to the demod so it knows to resync against the
+ newly tuned frequency */
+ s5h1411_softreset(fe);
+
return 0;
}
@@ -599,7 +624,7 @@ static int s5h1411_init(struct dvb_frontend *fe)
dprintk("%s()\n", __func__);
- s5h1411_sleep(fe, 0);
+ s5h1411_set_powerstate(fe, 0);
s5h1411_register_reset(fe);
for (i = 0; i < ARRAY_SIZE(init_tab); i++)
@@ -610,12 +635,17 @@ static int s5h1411_init(struct dvb_frontend *fe)
/* The datasheet says that after initialisation, VSB is default */
state->current_modulation = VSB_8;
+ /* Although the datasheet says it's in VSB, empirical evidence
+ shows problems getting lock on the first tuning request. Make
+ sure we call enable_modulation the first time around */
+ state->first_tune = 1;
+
if (state->config->output_mode == S5H1411_SERIAL_OUTPUT)
/* Serial */
- s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1101);
+ s5h1411_set_serialmode(fe, 1);
else
/* Parallel */
- s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1001);
+ s5h1411_set_serialmode(fe, 0);
s5h1411_set_spectralinversion(fe, state->config->inversion);
s5h1411_set_if_freq(fe, state->config->vsb_if);
@@ -637,28 +667,29 @@ static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status)
*status = 0;
- /* Get the demodulator status */
- reg = (s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2) >> 15)
- & 0x0001;
- if (reg)
- *status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ /* Register F2 bit 15 = Master Lock, removed */
switch (state->current_modulation) {
case QAM_64:
case QAM_256:
reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0);
- if (reg & 0x100)
- *status |= FE_HAS_VITERBI;
- if (reg & 0x10)
- *status |= FE_HAS_SYNC;
+ if (reg & 0x10) /* QAM FEC Lock */
+ *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+ if (reg & 0x100) /* QAM EQ Lock */
+ *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
break;
case VSB_8:
- reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x5e);
- if (reg & 0x0001)
- *status |= FE_HAS_SYNC;
reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2);
- if (reg & 0x1000)
- *status |= FE_HAS_VITERBI;
+ if (reg & 0x1000) /* FEC Lock */
+ *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+ if (reg & 0x2000) /* EQ Lock */
+ *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+ reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x53);
+ if (reg & 0x1) /* AFC Lock */
+ *status |= FE_HAS_SIGNAL;
+
break;
default:
return -EINVAL;
@@ -863,6 +894,7 @@ static struct dvb_frontend_ops s5h1411_ops = {
},
.init = s5h1411_init,
+ .sleep = s5h1411_sleep,
.i2c_gate_ctrl = s5h1411_i2c_gate_ctrl,
.set_frontend = s5h1411_set_frontend,
.get_frontend = s5h1411_get_frontend,
diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb/frontends/s5h1411.h
index 7d542bc00c4..45ec0f82989 100644
--- a/drivers/media/dvb/frontends/s5h1411.h
+++ b/drivers/media/dvb/frontends/s5h1411.h
@@ -47,7 +47,7 @@ struct s5h1411_config {
u16 mpeg_timing;
/* IF Freq for QAM and VSB in KHz */
-#define S5H1411_IF_2500 2500
+#define S5H1411_IF_3250 3250
#define S5H1411_IF_3500 3500
#define S5H1411_IF_4000 4000
#define S5H1411_IF_5380 5380
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
index 04e7f1cc140..2a8bbcd44cd 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -195,7 +195,7 @@ static struct init_tab {
static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
{
int ret;
- u8 buf [] = { reg, data };
+ u8 buf[] = { reg, data };
struct i2c_msg msg = {
.addr = state->config->demod_address,
.flags = 0, .buf = buf, .len = 2 };
@@ -213,9 +213,9 @@ static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
{
int ret;
- u8 b0 [] = { reg };
- u8 b1 [] = { 0 };
- struct i2c_msg msg [] = {
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+ struct i2c_msg msg[] = {
{ .addr = state->config->demod_address,
.flags = 0, .buf = b0, .len = 1 },
{ .addr = state->config->demod_address,
@@ -393,43 +393,89 @@ static int tda10048_get_tps(struct tda10048_state *state,
val = tda10048_readreg(state, TDA10048_OUT_CONF2);
switch ((val & 0x60) >> 5) {
- case 0: p->constellation = QPSK; break;
- case 1: p->constellation = QAM_16; break;
- case 2: p->constellation = QAM_64; break;
+ case 0:
+ p->constellation = QPSK;
+ break;
+ case 1:
+ p->constellation = QAM_16;
+ break;
+ case 2:
+ p->constellation = QAM_64;
+ break;
}
switch ((val & 0x18) >> 3) {
- case 0: p->hierarchy_information = HIERARCHY_NONE; break;
- case 1: p->hierarchy_information = HIERARCHY_1; break;
- case 2: p->hierarchy_information = HIERARCHY_2; break;
- case 3: p->hierarchy_information = HIERARCHY_4; break;
+ case 0:
+ p->hierarchy_information = HIERARCHY_NONE;
+ break;
+ case 1:
+ p->hierarchy_information = HIERARCHY_1;
+ break;
+ case 2:
+ p->hierarchy_information = HIERARCHY_2;
+ break;
+ case 3:
+ p->hierarchy_information = HIERARCHY_4;
+ break;
}
switch (val & 0x07) {
- case 0: p->code_rate_HP = FEC_1_2; break;
- case 1: p->code_rate_HP = FEC_2_3; break;
- case 2: p->code_rate_HP = FEC_3_4; break;
- case 3: p->code_rate_HP = FEC_5_6; break;
- case 4: p->code_rate_HP = FEC_7_8; break;
+ case 0:
+ p->code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ p->code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ p->code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ p->code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ p->code_rate_HP = FEC_7_8;
+ break;
}
val = tda10048_readreg(state, TDA10048_OUT_CONF3);
switch (val & 0x07) {
- case 0: p->code_rate_LP = FEC_1_2; break;
- case 1: p->code_rate_LP = FEC_2_3; break;
- case 2: p->code_rate_LP = FEC_3_4; break;
- case 3: p->code_rate_LP = FEC_5_6; break;
- case 4: p->code_rate_LP = FEC_7_8; break;
+ case 0:
+ p->code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ p->code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ p->code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ p->code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ p->code_rate_LP = FEC_7_8;
+ break;
}
val = tda10048_readreg(state, TDA10048_OUT_CONF1);
switch ((val & 0x0c) >> 2) {
- case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
- case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
- case 2: p->guard_interval = GUARD_INTERVAL_1_8; break;
- case 3: p->guard_interval = GUARD_INTERVAL_1_4; break;
+ case 0:
+ p->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ p->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ p->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ p->guard_interval = GUARD_INTERVAL_1_4;
+ break;
}
switch (val & 0x02) {
- case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
- case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+ case 0:
+ p->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ p->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
}
return 0;
diff --git a/drivers/media/dvb/frontends/z0194a.h b/drivers/media/dvb/frontends/z0194a.h
index d2876d2e176..07f3fc0998f 100644
--- a/drivers/media/dvb/frontends/z0194a.h
+++ b/drivers/media/dvb/frontends/z0194a.h
@@ -12,7 +12,7 @@
#ifndef Z0194A
#define Z0194A
-static int sharp_z0194a__set_symbol_rate(struct dvb_frontend *fe,
+static int sharp_z0194a_set_symbol_rate(struct dvb_frontend *fe,
u32 srate, u32 ratio)
{
u8 aclk = 0;
@@ -40,7 +40,7 @@ static int sharp_z0194a__set_symbol_rate(struct dvb_frontend *fe,
return 0;
}
-static u8 sharp_z0194a__inittab[] = {
+static u8 sharp_z0194a_inittab[] = {
0x01, 0x15,
0x02, 0x00,
0x03, 0x00,
@@ -82,16 +82,4 @@ static u8 sharp_z0194a__inittab[] = {
0xff, 0xff
};
-static struct stv0299_config sharp_z0194a_config = {
- .demod_address = 0x68,
- .inittab = sharp_z0194a__inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .skip_reinit = 0,
- .lock_output = STV0299_LOCKOUTPUT_1,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .set_symbol_rate = sharp_z0194a__set_symbol_rate,
-};
-
#endif
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index 9da260fe3fd..6f9b7736044 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -42,6 +42,10 @@ struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0x5510),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+ { USB_DEVICE(0x2040, 0x5520),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+ { USB_DEVICE(0x2040, 0x5530),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0x5580),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0x5590),
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index c7c770c2898..aa1ff524256 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -36,7 +36,6 @@
#include <linux/fs.h>
#include <linux/timer.h>
#include <linux/poll.h>
-#include <linux/byteorder/swabb.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
@@ -52,6 +51,7 @@
#include <linux/i2c.h>
#include <linux/kthread.h>
#include <asm/unaligned.h>
+#include <asm/byteorder.h>
#include <asm/system.h>
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index e51d707e58d..04cd7c04bdd 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -359,7 +359,7 @@ config USB_SI470X
computer's USB port.
To compile this driver as a module, choose M here: the
- module will be called radio-silabs.
+ module will be called radio-si470x.
config USB_MR800
tristate "AverMedia MR 800 USB FM radio support"
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 66783fffe4c..a5ca176a7b0 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -171,11 +171,11 @@ static int dsbr100_start(struct dsbr100_device *radio)
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
+ 0x00, 0xC7, radio->transfer_buffer, 8, 300) < 0 ||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_ONOFF,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
+ 0x01, 0x00, radio->transfer_buffer, 8, 300) < 0)
return -1;
radio->muted=0;
return (radio->transfer_buffer)[0];
@@ -188,11 +188,11 @@ static int dsbr100_stop(struct dsbr100_device *radio)
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
+ 0x16, 0x1C, radio->transfer_buffer, 8, 300) < 0 ||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_ONOFF,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
+ 0x00, 0x00, radio->transfer_buffer, 8, 300) < 0)
return -1;
radio->muted=1;
return (radio->transfer_buffer)[0];
@@ -201,24 +201,24 @@ static int dsbr100_stop(struct dsbr100_device *radio)
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
{
- freq = (freq/16*80)/1000+856;
+ freq = (freq / 16 * 80) / 1000 + 856;
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_TUNE,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- (freq>>8)&0x00ff, freq&0xff,
- radio->transfer_buffer, 8, 300)<0 ||
+ (freq >> 8) & 0x00ff, freq & 0xff,
+ radio->transfer_buffer, 8, 300) < 0 ||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
+ 0x96, 0xB7, radio->transfer_buffer, 8, 300) < 0 ||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
+ 0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) {
radio->stereo = -1;
return -1;
}
- radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
+ radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
return (radio->transfer_buffer)[0];
}
@@ -229,10 +229,10 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
+ 0x00 , 0x24, radio->transfer_buffer, 8, 300) < 0)
radio->stereo = -1;
else
- radio->stereo = ! (radio->transfer_buffer[0]&0x01);
+ radio->stereo = !(radio->transfer_buffer[0] & 0x01);
}
@@ -265,7 +265,7 @@ static int vidioc_querycap(struct file *file, void *priv,
{
strlcpy(v->driver, "dsbr100", sizeof(v->driver));
strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
- sprintf(v->bus_info, "ISA");
+ sprintf(v->bus_info, "USB");
v->version = RADIO_VERSION;
v->capabilities = V4L2_CAP_TUNER;
return 0;
@@ -282,9 +282,9 @@ static int vidioc_g_tuner(struct file *file, void *priv,
dsbr100_getstat(radio);
strcpy(v->name, "FM");
v->type = V4L2_TUNER_RADIO;
- v->rangelow = FREQ_MIN*FREQ_MUL;
- v->rangehigh = FREQ_MAX*FREQ_MUL;
- v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->rangelow = FREQ_MIN * FREQ_MUL;
+ v->rangehigh = FREQ_MAX * FREQ_MUL;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
v->capability = V4L2_TUNER_CAP_LOW;
if(radio->stereo)
v->audmode = V4L2_TUNER_MODE_STEREO;
@@ -309,8 +309,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
struct dsbr100_device *radio = video_drvdata(file);
radio->curfreq = f->frequency;
- if (dsbr100_setfreq(radio, radio->curfreq)==-1)
- warn("Set frequency failed");
+ if (dsbr100_setfreq(radio, radio->curfreq) == -1)
+ dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
return 0;
}
@@ -331,8 +331,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]),
- sizeof(*qc));
+ memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
return 0;
}
}
@@ -361,12 +360,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
case V4L2_CID_AUDIO_MUTE:
if (ctrl->value) {
if (dsbr100_stop(radio) == -1) {
- warn("Radio did not respond properly");
+ dev_warn(&radio->usbdev->dev,
+ "Radio did not respond properly\n");
return -EBUSY;
}
} else {
if (dsbr100_start(radio) == -1) {
- warn("Radio did not respond properly");
+ dev_warn(&radio->usbdev->dev,
+ "Radio did not respond properly\n");
return -EBUSY;
}
}
@@ -410,18 +411,25 @@ static int vidioc_s_audio(struct file *file, void *priv,
static int usb_dsbr100_open(struct inode *inode, struct file *file)
{
struct dsbr100_device *radio = video_drvdata(file);
+ int retval;
lock_kernel();
radio->users = 1;
radio->muted = 1;
- if (dsbr100_start(radio)<0) {
- warn("Radio did not start up properly");
+ if (dsbr100_start(radio) < 0) {
+ dev_warn(&radio->usbdev->dev,
+ "Radio did not start up properly\n");
radio->users = 0;
unlock_kernel();
return -EIO;
}
- dsbr100_setfreq(radio, radio->curfreq);
+
+ retval = dsbr100_setfreq(radio, radio->curfreq);
+
+ if (retval == -1)
+ printk(KERN_WARNING KBUILD_MODNAME ": Set frequency failed\n");
+
unlock_kernel();
return 0;
}
@@ -482,13 +490,20 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
{
struct dsbr100_device *radio;
- if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
+ radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
+
+ if (!radio)
return -ENOMEM;
- if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) {
+
+ radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL);
+
+ if (!(radio->transfer_buffer)) {
kfree(radio);
return -ENOMEM;
}
- if (!(radio->videodev = video_device_alloc())) {
+ radio->videodev = video_device_alloc();
+
+ if (!(radio->videodev)) {
kfree(radio->transfer_buffer);
kfree(radio);
return -ENOMEM;
@@ -498,10 +513,10 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
radio->removed = 0;
radio->users = 0;
radio->usbdev = interface_to_usbdev(intf);
- radio->curfreq = FREQ_MIN*FREQ_MUL;
+ radio->curfreq = FREQ_MIN * FREQ_MUL;
video_set_drvdata(radio->videodev, radio);
if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
- warn("Could not register video device");
+ dev_warn(&intf->dev, "Could not register video device\n");
video_device_release(radio->videodev);
kfree(radio->transfer_buffer);
kfree(radio);
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index a33717c4800..256cbeffdcb 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -469,16 +469,21 @@ static int usb_amradio_open(struct inode *inode, struct file *file)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+ lock_kernel();
+
radio->users = 1;
radio->muted = 1;
if (amradio_start(radio) < 0) {
warn("Radio did not start up properly");
radio->users = 0;
+ unlock_kernel();
return -EIO;
}
if (amradio_setfreq(radio, radio->curfreq) < 0)
warn("Set frequency failed");
+
+ unlock_kernel();
return 0;
}
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index f6cedcd3ab9..5920cd30697 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -104,6 +104,7 @@
* - hardware frequency seek support
* - afc indication
* - more safety checks, let si470x_get_freq return errno
+ * - vidioc behavior corrected according to v4l2 spec
*
* ToDo:
* - add firmware download/update support
@@ -141,9 +142,9 @@
/* USB Device ID List */
static struct usb_device_id si470x_usb_driver_id_table[] = {
/* Silicon Labs USB FM Radio Reference Design */
- { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
/* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
- { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
/* Terminating entry */
{ }
};
@@ -157,7 +158,7 @@ MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
/* Radio Nr */
static int radio_nr = -1;
-module_param(radio_nr, int, 0);
+module_param(radio_nr, int, 0444);
MODULE_PARM_DESC(radio_nr, "Radio Nr");
/* Spacing (kHz) */
@@ -165,42 +166,42 @@ MODULE_PARM_DESC(radio_nr, "Radio Nr");
/* 1: 100 kHz (Europe, Japan) */
/* 2: 50 kHz */
static unsigned short space = 2;
-module_param(space, ushort, 0);
-MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
+module_param(space, ushort, 0444);
+MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
/* Bottom of Band (MHz) */
/* 0: 87.5 - 108 MHz (USA, Europe)*/
/* 1: 76 - 108 MHz (Japan wide band) */
/* 2: 76 - 90 MHz (Japan) */
static unsigned short band = 1;
-module_param(band, ushort, 0);
-MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
+module_param(band, ushort, 0444);
+MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
/* De-emphasis */
/* 0: 75 us (USA) */
/* 1: 50 us (Europe, Australia, Japan) */
static unsigned short de = 1;
-module_param(de, ushort, 0);
-MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*");
+module_param(de, ushort, 0444);
+MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
/* USB timeout */
static unsigned int usb_timeout = 500;
-module_param(usb_timeout, uint, 0);
+module_param(usb_timeout, uint, 0644);
MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
/* Tune timeout */
static unsigned int tune_timeout = 3000;
-module_param(tune_timeout, uint, 0);
+module_param(tune_timeout, uint, 0644);
MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
/* Seek timeout */
static unsigned int seek_timeout = 5000;
-module_param(seek_timeout, uint, 0);
+module_param(seek_timeout, uint, 0644);
MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
/* RDS buffer blocks */
static unsigned int rds_buf = 100;
-module_param(rds_buf, uint, 0);
+module_param(rds_buf, uint, 0444);
MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
/* RDS maximum block errors */
@@ -209,7 +210,7 @@ static unsigned short max_rds_errors = 1;
/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */
/* 2 means 3-5 errors requiring correction */
/* 3 means 6+ errors or errors in checkword, correction not possible */
-module_param(max_rds_errors, ushort, 0);
+module_param(max_rds_errors, ushort, 0644);
MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
/* RDS poll frequency */
@@ -218,7 +219,7 @@ static unsigned int rds_poll_time = 40;
/* 50 is used by radio-cadet */
/* 75 should be okay */
/* 80 is the usual RDS receive interval */
-module_param(rds_poll_time, uint, 0);
+module_param(rds_poll_time, uint, 0644);
MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
@@ -667,23 +668,29 @@ static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
int retval;
/* Spacing (kHz) */
- switch (space) {
+ switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
/* 0: 200 kHz (USA, Australia) */
- case 0 : spacing = 0.200 * FREQ_MUL; break;
+ case 0:
+ spacing = 0.200 * FREQ_MUL; break;
/* 1: 100 kHz (Europe, Japan) */
- case 1 : spacing = 0.100 * FREQ_MUL; break;
+ case 1:
+ spacing = 0.100 * FREQ_MUL; break;
/* 2: 50 kHz */
- default: spacing = 0.050 * FREQ_MUL; break;
+ default:
+ spacing = 0.050 * FREQ_MUL; break;
};
/* Bottom of Band (MHz) */
- switch (band) {
+ switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
/* 0: 87.5 - 108 MHz (USA, Europe) */
- case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+ case 0:
+ band_bottom = 87.5 * FREQ_MUL; break;
/* 1: 76 - 108 MHz (Japan wide band) */
- default: band_bottom = 76 * FREQ_MUL; break;
+ default:
+ band_bottom = 76 * FREQ_MUL; break;
/* 2: 76 - 90 MHz (Japan) */
- case 2 : band_bottom = 76 * FREQ_MUL; break;
+ case 2:
+ band_bottom = 76 * FREQ_MUL; break;
};
/* read channel */
@@ -706,23 +713,29 @@ static int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
unsigned short chan;
/* Spacing (kHz) */
- switch (space) {
+ switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
/* 0: 200 kHz (USA, Australia) */
- case 0 : spacing = 0.200 * FREQ_MUL; break;
+ case 0:
+ spacing = 0.200 * FREQ_MUL; break;
/* 1: 100 kHz (Europe, Japan) */
- case 1 : spacing = 0.100 * FREQ_MUL; break;
+ case 1:
+ spacing = 0.100 * FREQ_MUL; break;
/* 2: 50 kHz */
- default: spacing = 0.050 * FREQ_MUL; break;
+ default:
+ spacing = 0.050 * FREQ_MUL; break;
};
/* Bottom of Band (MHz) */
- switch (band) {
+ switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
/* 0: 87.5 - 108 MHz (USA, Europe) */
- case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+ case 0:
+ band_bottom = 87.5 * FREQ_MUL; break;
/* 1: 76 - 108 MHz (Japan wide band) */
- default: band_bottom = 76 * FREQ_MUL; break;
+ default:
+ band_bottom = 76 * FREQ_MUL; break;
/* 2: 76 - 90 MHz (Japan) */
- case 2 : band_bottom = 76 * FREQ_MUL; break;
+ case 2:
+ band_bottom = 76 * FREQ_MUL; break;
};
/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
@@ -1164,7 +1177,6 @@ static const struct file_operations si470x_fops = {
* si470x_v4l2_queryctrl - query control
*/
static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
-/* HINT: the disabled controls are only here to satify kradio and such apps */
{
.id = V4L2_CID_AUDIO_VOLUME,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -1175,18 +1187,6 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
.default_value = 15,
},
{
- .id = V4L2_CID_AUDIO_BALANCE,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_AUDIO_BASS,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_AUDIO_TREBLE,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
.id = V4L2_CID_AUDIO_MUTE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Mute",
@@ -1195,10 +1195,6 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
.step = 1,
.default_value = 1,
},
- {
- .id = V4L2_CID_AUDIO_LOUDNESS,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
};
@@ -1220,56 +1216,34 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
/*
- * si470x_vidioc_g_input - get input
- */
-static int si470x_vidioc_g_input(struct file *file, void *priv,
- unsigned int *i)
-{
- *i = 0;
-
- return 0;
-}
-
-
-/*
- * si470x_vidioc_s_input - set input
- */
-static int si470x_vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- int retval = 0;
-
- /* safety checks */
- if (i != 0)
- retval = -EINVAL;
-
- if (retval < 0)
- printk(KERN_WARNING DRIVER_NAME
- ": set input failed with %d\n", retval);
- return retval;
-}
-
-
-/*
* si470x_vidioc_queryctrl - enumerate control items
*/
static int si470x_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
- unsigned char i;
+ unsigned char i = 0;
int retval = -EINVAL;
- /* safety checks */
- if (!qc->id)
+ /* abort if qc->id is below V4L2_CID_BASE */
+ if (qc->id < V4L2_CID_BASE)
goto done;
+ /* search video control */
for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
if (qc->id == si470x_v4l2_queryctrl[i].id) {
memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
- retval = 0;
+ retval = 0; /* found */
break;
}
}
+ /* disable unsupported base controls */
+ /* to satisfy kradio and such apps */
+ if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
+ qc->flags = V4L2_CTRL_FLAG_DISABLED;
+ retval = 0;
+ }
+
done:
if (retval < 0)
printk(KERN_WARNING DRIVER_NAME
@@ -1360,44 +1334,13 @@ done:
static int si470x_vidioc_g_audio(struct file *file, void *priv,
struct v4l2_audio *audio)
{
- int retval = 0;
-
- /* safety checks */
- if (audio->index != 0) {
- retval = -EINVAL;
- goto done;
- }
-
+ /* driver constants */
+ audio->index = 0;
strcpy(audio->name, "Radio");
audio->capability = V4L2_AUDCAP_STEREO;
+ audio->mode = 0;
-done:
- if (retval < 0)
- printk(KERN_WARNING DRIVER_NAME
- ": get audio failed with %d\n", retval);
- return retval;
-}
-
-
-/*
- * si470x_vidioc_s_audio - set audio attributes
- */
-static int si470x_vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *audio)
-{
- int retval = 0;
-
- /* safety checks */
- if (audio->index != 0) {
- retval = -EINVAL;
- goto done;
- }
-
-done:
- if (retval < 0)
- printk(KERN_WARNING DRIVER_NAME
- ": set audio failed with %d\n", retval);
- return retval;
+ return 0;
}
@@ -1415,7 +1358,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
retval = -EIO;
goto done;
}
- if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
+ if (tuner->index != 0) {
retval = -EINVAL;
goto done;
}
@@ -1424,8 +1367,13 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
if (retval < 0)
goto done;
+ /* driver constants */
strcpy(tuner->name, "FM");
- switch (band) {
+ tuner->type = V4L2_TUNER_RADIO;
+ tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+
+ /* range limits */
+ switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
/* 0: 87.5 - 108 MHz (USA, Europe, default) */
default:
tuner->rangelow = 87.5 * FREQ_MUL;
@@ -1442,14 +1390,18 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
tuner->rangehigh = 90 * FREQ_MUL;
break;
};
- tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- tuner->capability = V4L2_TUNER_CAP_LOW;
- /* Stereo indicator == Stereo (instead of Mono) */
+ /* stereo indicator == stereo (instead of mono) */
if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
- tuner->audmode = V4L2_TUNER_MODE_STEREO;
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
else
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+ /* mono/stereo selector */
+ if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 1)
tuner->audmode = V4L2_TUNER_MODE_MONO;
+ else
+ tuner->audmode = V4L2_TUNER_MODE_STEREO;
/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
@@ -1474,22 +1426,27 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *tuner)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
+ int retval = -EINVAL;
/* safety checks */
if (radio->disconnected) {
retval = -EIO;
goto done;
}
- if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
- retval = -EINVAL;
+ if (tuner->index != 0)
goto done;
- }
- if (tuner->audmode == V4L2_TUNER_MODE_MONO)
+ /* mono/stereo selector */
+ switch (tuner->audmode) {
+ case V4L2_TUNER_MODE_MONO:
radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */
- else
+ break;
+ case V4L2_TUNER_MODE_STEREO:
radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
+ break;
+ default:
+ goto done;
+ }
retval = si470x_set_register(radio, POWERCFG);
@@ -1515,11 +1472,12 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
retval = -EIO;
goto done;
}
- if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
+ if (freq->tuner != 0) {
retval = -EINVAL;
goto done;
}
+ freq->type = V4L2_TUNER_RADIO;
retval = si470x_get_freq(radio, &freq->frequency);
done:
@@ -1544,7 +1502,7 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
retval = -EIO;
goto done;
}
- if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
+ if (freq->tuner != 0) {
retval = -EINVAL;
goto done;
}
@@ -1573,7 +1531,7 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
retval = -EIO;
goto done;
}
- if ((seek->tuner != 0) && (seek->type != V4L2_TUNER_RADIO)) {
+ if (seek->tuner != 0) {
retval = -EINVAL;
goto done;
}
@@ -1588,15 +1546,16 @@ done:
return retval;
}
+
+/*
+ * si470x_ioctl_ops - video device ioctl operations
+ */
static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
.vidioc_querycap = si470x_vidioc_querycap,
- .vidioc_g_input = si470x_vidioc_g_input,
- .vidioc_s_input = si470x_vidioc_s_input,
.vidioc_queryctrl = si470x_vidioc_queryctrl,
.vidioc_g_ctrl = si470x_vidioc_g_ctrl,
.vidioc_s_ctrl = si470x_vidioc_s_ctrl,
.vidioc_g_audio = si470x_vidioc_g_audio,
- .vidioc_s_audio = si470x_vidioc_s_audio,
.vidioc_g_tuner = si470x_vidioc_g_tuner,
.vidioc_s_tuner = si470x_vidioc_s_tuner,
.vidioc_g_frequency = si470x_vidioc_g_frequency,
@@ -1604,14 +1563,15 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
.vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek,
};
+
/*
- * si470x_viddev_tamples - video device interface
+ * si470x_viddev_template - video device interface
*/
static struct video_device si470x_viddev_template = {
.fops = &si470x_fops,
- .ioctl_ops = &si470x_ioctl_ops,
.name = DRIVER_NAME,
.release = video_device_release,
+ .ioctl_ops = &si470x_ioctl_ops,
};
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index f794f2dbfb3..e0eb4f32144 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -29,43 +29,24 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
#include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
#include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/videodev.h>
#include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
MODULE_LICENSE("GPL");
-
-#define I2C_NAME(x) (x)->name
-
-
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
/* ----------------------------------------------------------------------- */
struct adv7170 {
@@ -80,21 +61,12 @@ struct adv7170 {
int sat;
};
-#define I2C_ADV7170 0xd4
-#define I2C_ADV7171 0x54
-
-static char adv7170_name[] = "adv7170";
-static char adv7171_name[] = "adv7171";
-
static char *inputs[] = { "pass_through", "play_back" };
static char *norms[] = { "PAL", "NTSC" };
/* ----------------------------------------------------------------------- */
-static inline int
-adv7170_write (struct i2c_client *client,
- u8 reg,
- u8 value)
+static inline int adv7170_write(struct i2c_client *client, u8 reg, u8 value)
{
struct adv7170 *encoder = i2c_get_clientdata(client);
@@ -102,17 +74,13 @@ adv7170_write (struct i2c_client *client,
return i2c_smbus_write_byte_data(client, reg, value);
}
-static inline int
-adv7170_read (struct i2c_client *client,
- u8 reg)
+static inline int adv7170_read(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
-static int
-adv7170_write_block (struct i2c_client *client,
- const u8 *data,
- unsigned int len)
+static int adv7170_write_block(struct i2c_client *client,
+ const u8 *data, unsigned int len)
{
int ret = -1;
u8 reg;
@@ -133,33 +101,25 @@ adv7170_write_block (struct i2c_client *client,
encoder->reg[reg++] = data[1];
len -= 2;
data += 2;
- } while (len >= 2 && data[0] == reg &&
- block_len < 32);
- if ((ret = i2c_master_send(client, block_data,
- block_len)) < 0)
+ } while (len >= 2 && data[0] == reg && block_len < 32);
+ ret = i2c_master_send(client, block_data, block_len);
+ if (ret < 0)
break;
}
} else {
/* do some slow I2C emulation kind of thing */
while (len >= 2) {
reg = *data++;
- if ((ret = adv7170_write(client, reg,
- *data++)) < 0)
+ ret = adv7170_write(client, reg, *data++);
+ if (ret < 0)
break;
len -= 2;
}
}
-
return ret;
}
/* ----------------------------------------------------------------------- */
-// Output filter: S-Video Composite
-
-#define MR050 0x11 //0x09
-#define MR060 0x14 //0x0c
-
-//---------------------------------------------------------------------------
#define TR0MODE 0x4c
#define TR0RST 0x80
@@ -167,7 +127,6 @@ adv7170_write_block (struct i2c_client *client,
#define TR1CAPT 0x00
#define TR1PLAY 0x00
-
static const unsigned char init_NTSC[] = {
0x00, 0x10, // MR0
0x01, 0x20, // MR1
@@ -227,15 +186,11 @@ static const unsigned char init_PAL[] = {
};
-static int
-adv7170_command (struct i2c_client *client,
- unsigned int cmd,
- void * arg)
+static int adv7170_command(struct i2c_client *client, unsigned cmd, void *arg)
{
struct adv7170 *encoder = i2c_get_clientdata(client);
switch (cmd) {
-
case 0:
#if 0
/* This is just for testing!!! */
@@ -254,18 +209,16 @@ adv7170_command (struct i2c_client *client,
VIDEO_ENCODER_NTSC;
cap->inputs = 2;
cap->outputs = 1;
- }
break;
+ }
case ENCODER_SET_NORM:
{
int iarg = *(int *) arg;
- dprintk(1, KERN_DEBUG "%s_command: set norm %d",
- I2C_NAME(client), iarg);
+ v4l_dbg(1, debug, client, "set norm %d\n", iarg);
switch (iarg) {
-
case VIDEO_MODE_NTSC:
adv7170_write_block(client, init_NTSC,
sizeof(init_NTSC));
@@ -285,16 +238,13 @@ adv7170_command (struct i2c_client *client,
break;
default:
- dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
- I2C_NAME(client), iarg);
+ v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
return -EINVAL;
-
}
- dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
- norms[iarg]);
+ v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
encoder->norm = iarg;
- }
break;
+ }
case ENCODER_SET_INPUT:
{
@@ -304,19 +254,17 @@ adv7170_command (struct i2c_client *client,
*iarg = 1: input is from ZR36060
*iarg = 2: color bar */
- dprintk(1, KERN_DEBUG "%s_command: set input from %s\n",
- I2C_NAME(client),
+ v4l_dbg(1, debug, client, "set input from %s\n",
iarg == 0 ? "decoder" : "ZR36060");
switch (iarg) {
-
case 0:
adv7170_write(client, 0x01, 0x20);
adv7170_write(client, 0x08, TR1CAPT); /* TR1 */
adv7170_write(client, 0x02, 0x0e); // Enable genlock
adv7170_write(client, 0x07, TR0MODE | TR0RST);
adv7170_write(client, 0x07, TR0MODE);
- //udelay(10);
+ /* udelay(10); */
break;
case 1:
@@ -325,20 +273,17 @@ adv7170_command (struct i2c_client *client,
adv7170_write(client, 0x02, 0x08);
adv7170_write(client, 0x07, TR0MODE | TR0RST);
adv7170_write(client, 0x07, TR0MODE);
- //udelay(10);
+ /* udelay(10); */
break;
default:
- dprintk(1, KERN_ERR "%s: illegal input: %d\n",
- I2C_NAME(client), iarg);
+ v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
return -EINVAL;
-
}
- dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
- inputs[iarg]);
+ v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
encoder->input = iarg;
- }
break;
+ }
case ENCODER_SET_OUTPUT:
{
@@ -348,16 +293,16 @@ adv7170_command (struct i2c_client *client,
if (*iarg != 0) {
return -EINVAL;
}
- }
break;
+ }
case ENCODER_ENABLE_OUTPUT:
{
int *iarg = arg;
encoder->enable = !!*iarg;
- }
break;
+ }
default:
return -EINVAL;
@@ -368,149 +313,67 @@ adv7170_command (struct i2c_client *client,
/* ----------------------------------------------------------------------- */
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] =
- { I2C_ADV7170 >> 1, (I2C_ADV7170 >> 1) + 1,
- I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1,
+static unsigned short normal_i2c[] = {
+ 0xd4 >> 1, 0xd6 >> 1, /* adv7170 IDs */
+ 0x54 >> 1, 0x56 >> 1, /* adv7171 IDs */
I2C_CLIENT_END
};
-static unsigned short ignore = I2C_CLIENT_END;
+I2C_CLIENT_INSMOD;
-static struct i2c_client_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .probe = &ignore,
- .ignore = &ignore,
-};
-
-static struct i2c_driver i2c_driver_adv7170;
-
-static int
-adv7170_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
+static int adv7170_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int i;
- struct i2c_client *client;
struct adv7170 *encoder;
- char *dname;
-
- dprintk(1,
- KERN_INFO
- "adv7170.c: detecting adv7170 client on address 0x%x\n",
- address << 1);
+ int i;
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return 0;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_adv7170;
- if ((client->addr == I2C_ADV7170 >> 1) ||
- (client->addr == (I2C_ADV7170 >> 1) + 1)) {
- dname = adv7170_name;
- } else if ((client->addr == I2C_ADV7171 >> 1) ||
- (client->addr == (I2C_ADV7171 >> 1) + 1)) {
- dname = adv7171_name;
- } else {
- /* We should never get here!!! */
- kfree(client);
- return 0;
- }
- strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
- if (encoder == NULL) {
- kfree(client);
+ if (encoder == NULL)
return -ENOMEM;
- }
encoder->norm = VIDEO_MODE_NTSC;
encoder->input = 0;
encoder->enable = 1;
i2c_set_clientdata(client, encoder);
- i = i2c_attach_client(client);
- if (i) {
- kfree(client);
- kfree(encoder);
- return i;
- }
-
i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC));
if (i >= 0) {
i = adv7170_write(client, 0x07, TR0MODE | TR0RST);
i = adv7170_write(client, 0x07, TR0MODE);
i = adv7170_read(client, 0x12);
- dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%02x\n",
- I2C_NAME(client), i & 1, client->addr << 1);
- }
- if (i < 0) {
- dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
- I2C_NAME(client), i);
+ v4l_dbg(1, debug, client, "revision %d\n", i & 1);
}
-
+ if (i < 0)
+ v4l_dbg(1, debug, client, "init error 0x%x\n", i);
return 0;
}
-static int
-adv7170_attach_adapter (struct i2c_adapter *adapter)
-{
- dprintk(1,
- KERN_INFO
- "adv7170.c: starting probe for adapter %s (0x%x)\n",
- I2C_NAME(adapter), adapter->id);
- return i2c_probe(adapter, &addr_data, &adv7170_detect_client);
-}
-
-static int
-adv7170_detach_client (struct i2c_client *client)
+static int adv7170_remove(struct i2c_client *client)
{
- struct adv7170 *encoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
-
- kfree(encoder);
- kfree(client);
-
+ kfree(i2c_get_clientdata(client));
return 0;
}
/* ----------------------------------------------------------------------- */
-static struct i2c_driver i2c_driver_adv7170 = {
- .driver = {
- .name = "adv7170", /* name */
- },
-
- .id = I2C_DRIVERID_ADV7170,
+static const struct i2c_device_id adv7170_id[] = {
+ { "adv7170", 0 },
+ { "adv7171", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adv7170_id);
- .attach_adapter = adv7170_attach_adapter,
- .detach_client = adv7170_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "adv7170",
+ .driverid = I2C_DRIVERID_ADV7170,
.command = adv7170_command,
+ .probe = adv7170_probe,
+ .remove = adv7170_remove,
+ .id_table = adv7170_id,
};
-
-static int __init
-adv7170_init (void)
-{
- return i2c_add_driver(&i2c_driver_adv7170);
-}
-
-static void __exit
-adv7170_exit (void)
-{
- i2c_del_driver(&i2c_driver_adv7170);
-}
-
-module_init(adv7170_init);
-module_exit(adv7170_exit);
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 8ee07a68f70..6008e84653f 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -25,43 +25,24 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
#include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
#include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/videodev.h>
#include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-
-#define I2C_NAME(s) (s)->name
-
-
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
/* ----------------------------------------------------------------------- */
struct adv7175 {
@@ -77,33 +58,23 @@ struct adv7175 {
#define I2C_ADV7175 0xd4
#define I2C_ADV7176 0x54
-static char adv7175_name[] = "adv7175";
-static char adv7176_name[] = "adv7176";
-
static char *inputs[] = { "pass_through", "play_back", "color_bar" };
static char *norms[] = { "PAL", "NTSC", "SECAM->PAL (may not work!)" };
/* ----------------------------------------------------------------------- */
-static inline int
-adv7175_write (struct i2c_client *client,
- u8 reg,
- u8 value)
+static inline int adv7175_write(struct i2c_client *client, u8 reg, u8 value)
{
return i2c_smbus_write_byte_data(client, reg, value);
}
-static inline int
-adv7175_read (struct i2c_client *client,
- u8 reg)
+static inline int adv7175_read(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
-static int
-adv7175_write_block (struct i2c_client *client,
- const u8 *data,
- unsigned int len)
+static int adv7175_write_block(struct i2c_client *client,
+ const u8 *data, unsigned int len)
{
int ret = -1;
u8 reg;
@@ -123,18 +94,17 @@ adv7175_write_block (struct i2c_client *client,
reg++;
len -= 2;
data += 2;
- } while (len >= 2 && data[0] == reg &&
- block_len < 32);
- if ((ret = i2c_master_send(client, block_data,
- block_len)) < 0)
+ } while (len >= 2 && data[0] == reg && block_len < 32);
+ ret = i2c_master_send(client, block_data, block_len);
+ if (ret < 0)
break;
}
} else {
/* do some slow I2C emulation kind of thing */
while (len >= 2) {
reg = *data++;
- if ((ret = adv7175_write(client, reg,
- *data++)) < 0)
+ ret = adv7175_write(client, reg, *data++);
+ if (ret < 0)
break;
len -= 2;
}
@@ -143,13 +113,11 @@ adv7175_write_block (struct i2c_client *client,
return ret;
}
-static void
-set_subcarrier_freq (struct i2c_client *client,
- int pass_through)
+static void set_subcarrier_freq(struct i2c_client *client, int pass_through)
{
/* for some reason pass_through NTSC needs
* a different sub-carrier freq to remain stable. */
- if(pass_through)
+ if (pass_through)
adv7175_write(client, 0x02, 0x00);
else
adv7175_write(client, 0x02, 0x55);
@@ -160,12 +128,12 @@ set_subcarrier_freq (struct i2c_client *client,
}
/* ----------------------------------------------------------------------- */
-// Output filter: S-Video Composite
+/* Output filter: S-Video Composite */
-#define MR050 0x11 //0x09
-#define MR060 0x14 //0x0c
+#define MR050 0x11 /* 0x09 */
+#define MR060 0x14 /* 0x0c */
-//---------------------------------------------------------------------------
+/* ----------------------------------------------------------------------- */
#define TR0MODE 0x46
#define TR0RST 0x80
@@ -216,15 +184,11 @@ static const unsigned char init_ntsc[] = {
0x06, 0x1a, /* subc. phase */
};
-static int
-adv7175_command (struct i2c_client *client,
- unsigned int cmd,
- void *arg)
+static int adv7175_command(struct i2c_client *client, unsigned cmd, void *arg)
{
struct adv7175 *encoder = i2c_get_clientdata(client);
switch (cmd) {
-
case 0:
/* This is just for testing!!! */
adv7175_write_block(client, init_common,
@@ -242,15 +206,14 @@ adv7175_command (struct i2c_client *client,
VIDEO_ENCODER_SECAM; /* well, hacky */
cap->inputs = 2;
cap->outputs = 1;
- }
break;
+ }
case ENCODER_SET_NORM:
{
int iarg = *(int *) arg;
switch (iarg) {
-
case VIDEO_MODE_NTSC:
adv7175_write_block(client, init_ntsc,
sizeof(init_ntsc));
@@ -284,16 +247,13 @@ adv7175_command (struct i2c_client *client,
adv7175_write(client, 0x07, TR0MODE);
break;
default:
- dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
- I2C_NAME(client), iarg);
+ v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
return -EINVAL;
-
}
- dprintk(1, KERN_INFO "%s: switched to %s\n", I2C_NAME(client),
- norms[iarg]);
+ v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
encoder->norm = iarg;
- }
break;
+ }
case ENCODER_SET_INPUT:
{
@@ -304,7 +264,6 @@ adv7175_command (struct i2c_client *client,
*iarg = 2: color bar */
switch (iarg) {
-
case 0:
adv7175_write(client, 0x01, 0x00);
@@ -331,7 +290,7 @@ adv7175_command (struct i2c_client *client,
adv7175_write(client, 0x0d, 0x49);
adv7175_write(client, 0x07, TR0MODE | TR0RST);
adv7175_write(client, 0x07, TR0MODE);
- //udelay(10);
+ /* udelay(10); */
break;
case 2:
@@ -343,39 +302,35 @@ adv7175_command (struct i2c_client *client,
adv7175_write(client, 0x0d, 0x49);
adv7175_write(client, 0x07, TR0MODE | TR0RST);
adv7175_write(client, 0x07, TR0MODE);
- //udelay(10);
+ /* udelay(10); */
break;
default:
- dprintk(1, KERN_ERR "%s: illegal input: %d\n",
- I2C_NAME(client), iarg);
+ v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
return -EINVAL;
-
}
- dprintk(1, KERN_INFO "%s: switched to %s\n", I2C_NAME(client),
- inputs[iarg]);
+ v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
encoder->input = iarg;
- }
break;
+ }
case ENCODER_SET_OUTPUT:
{
int *iarg = arg;
/* not much choice of outputs */
- if (*iarg != 0) {
+ if (*iarg != 0)
return -EINVAL;
- }
- }
break;
+ }
case ENCODER_ENABLE_OUTPUT:
{
int *iarg = arg;
encoder->enable = !!*iarg;
- }
break;
+ }
default:
return -EINVAL;
@@ -390,145 +345,67 @@ adv7175_command (struct i2c_client *client,
* Generic i2c probe
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static unsigned short normal_i2c[] =
- { I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
+static unsigned short normal_i2c[] = {
+ I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1,
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 struct i2c_driver i2c_driver_adv7175;
+I2C_CLIENT_INSMOD;
-static int
-adv7175_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
+static int adv7175_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int i;
- struct i2c_client *client;
struct adv7175 *encoder;
- char *dname;
-
- dprintk(1,
- KERN_INFO
- "adv7175.c: detecting adv7175 client on address 0x%x\n",
- address << 1);
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return 0;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_adv7175;
- if ((client->addr == I2C_ADV7175 >> 1) ||
- (client->addr == (I2C_ADV7175 >> 1) + 1)) {
- dname = adv7175_name;
- } else if ((client->addr == I2C_ADV7176 >> 1) ||
- (client->addr == (I2C_ADV7176 >> 1) + 1)) {
- dname = adv7176_name;
- } else {
- /* We should never get here!!! */
- kfree(client);
- return 0;
- }
- strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
- if (encoder == NULL) {
- kfree(client);
+ if (encoder == NULL)
return -ENOMEM;
- }
encoder->norm = VIDEO_MODE_PAL;
encoder->input = 0;
encoder->enable = 1;
i2c_set_clientdata(client, encoder);
- i = i2c_attach_client(client);
- if (i) {
- kfree(client);
- kfree(encoder);
- return i;
- }
-
i = adv7175_write_block(client, init_common, sizeof(init_common));
if (i >= 0) {
i = adv7175_write(client, 0x07, TR0MODE | TR0RST);
i = adv7175_write(client, 0x07, TR0MODE);
i = adv7175_read(client, 0x12);
- dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%x\n",
- I2C_NAME(client), i & 1, client->addr << 1);
+ v4l_dbg(1, debug, client, "revision %d\n", i & 1);
}
- if (i < 0) {
- dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
- I2C_NAME(client), i);
- }
-
+ if (i < 0)
+ v4l_dbg(1, debug, client, "init error 0x%x\n", i);
return 0;
}
-static int
-adv7175_attach_adapter (struct i2c_adapter *adapter)
-{
- dprintk(1,
- KERN_INFO
- "adv7175.c: starting probe for adapter %s (0x%x)\n",
- I2C_NAME(adapter), adapter->id);
- return i2c_probe(adapter, &addr_data, &adv7175_detect_client);
-}
-
-static int
-adv7175_detach_client (struct i2c_client *client)
+static int adv7175_remove(struct i2c_client *client)
{
- struct adv7175 *encoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
-
- kfree(encoder);
- kfree(client);
-
+ kfree(i2c_get_clientdata(client));
return 0;
}
/* ----------------------------------------------------------------------- */
-static struct i2c_driver i2c_driver_adv7175 = {
- .driver = {
- .name = "adv7175", /* name */
- },
-
- .id = I2C_DRIVERID_ADV7175,
+static const struct i2c_device_id adv7175_id[] = {
+ { "adv7175", 0 },
+ { "adv7176", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adv7175_id);
- .attach_adapter = adv7175_attach_adapter,
- .detach_client = adv7175_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "adv7175",
+ .driverid = I2C_DRIVERID_ADV7175,
.command = adv7175_command,
+ .probe = adv7175_probe,
+ .remove = adv7175_remove,
+ .id_table = adv7175_id,
};
-
-static int __init
-adv7175_init (void)
-{
- return i2c_add_driver(&i2c_driver_adv7175);
-}
-
-static void __exit
-adv7175_exit (void)
-{
- i2c_del_driver(&i2c_driver_adv7175);
-}
-
-module_init(adv7175_init);
-module_exit(adv7175_exit);
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 218754b4906..e09b0069323 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -866,7 +866,7 @@ static int __init ar_init(void)
}
printk("video%d: Found M64278 VGA (IRQ %d, Freq %dMHz).\n",
- ar->vdev->minor, M32R_IRQ_INT3, freq);
+ ar->vdev->num, M32R_IRQ_INT3, freq);
return 0;
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 5f07a8a072b..d60123b413f 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -90,6 +90,7 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */
+ case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
break;
@@ -185,7 +186,7 @@ void au0828_gpio_setup(struct au0828_dev *dev)
}
/* table of devices that work with this driver */
-struct usb_device_id au0828_usb_id_table [] = {
+struct usb_device_id au0828_usb_id_table[] = {
{ USB_DEVICE(0x2040, 0x7200),
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ USB_DEVICE(0x2040, 0x7240),
@@ -198,6 +199,8 @@ struct usb_device_id au0828_usb_id_table [] = {
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ USB_DEVICE(0x2040, 0x721b),
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x721e),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ USB_DEVICE(0x2040, 0x721f),
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ USB_DEVICE(0x2040, 0x7280),
diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
index d856de9f742..5765e865637 100644
--- a/drivers/media/video/au0828/au0828-core.c
+++ b/drivers/media/video/au0828/au0828-core.c
@@ -91,7 +91,8 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
status = usb_control_msg(dev->usbdev,
usb_sndctrlpipe(dev->usbdev, 0),
request,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE,
value, index,
cp, size, 1000);
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index f0fcdb4769d..a882cf546d0 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -173,7 +173,8 @@ static int start_urb_transfer(struct au0828_dev *dev)
purb->status = -EINPROGRESS;
usb_fill_bulk_urb(purb,
dev->usbdev,
- usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE),
+ usb_rcvbulkpipe(dev->usbdev,
+ _AU0828_BULKPIPE),
purb->transfer_buffer,
URB_BUFSIZE,
urb_completion,
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index ddd2a7964de..a07b7b88e5b 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -29,44 +29,25 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
#include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
#include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/videodev.h>
#include <linux/video_decoder.h>
-
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
MODULE_LICENSE("GPL");
-
-#define I2C_NAME(s) (s)->name
-
-
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
/* ----------------------------------------------------------------------- */
struct bt819 {
@@ -97,14 +78,9 @@ static struct timing timing_data[] = {
{858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
};
-#define I2C_BT819 0x8a
-
/* ----------------------------------------------------------------------- */
-static inline int
-bt819_write (struct i2c_client *client,
- u8 reg,
- u8 value)
+static inline int bt819_write(struct i2c_client *client, u8 reg, u8 value)
{
struct bt819 *decoder = i2c_get_clientdata(client);
@@ -112,24 +88,15 @@ bt819_write (struct i2c_client *client,
return i2c_smbus_write_byte_data(client, reg, value);
}
-static inline int
-bt819_setbit (struct i2c_client *client,
- u8 reg,
- u8 bit,
- u8 value)
+static inline int bt819_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
{
struct bt819 *decoder = i2c_get_clientdata(client);
return bt819_write(client, reg,
- (decoder->
- reg[reg] & ~(1 << bit)) |
- (value ? (1 << bit) : 0));
+ (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0));
}
-static int
-bt819_write_block (struct i2c_client *client,
- const u8 *data,
- unsigned int len)
+static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
{
int ret = -1;
u8 reg;
@@ -150,10 +117,9 @@ bt819_write_block (struct i2c_client *client,
decoder->reg[reg++] = data[1];
len -= 2;
data += 2;
- } while (len >= 2 && data[0] == reg &&
- block_len < 32);
- if ((ret = i2c_master_send(client, block_data,
- block_len)) < 0)
+ } while (len >= 2 && data[0] == reg && block_len < 32);
+ ret = i2c_master_send(client, block_data, block_len);
+ if (ret < 0)
break;
}
} else {
@@ -169,20 +135,17 @@ bt819_write_block (struct i2c_client *client,
return ret;
}
-static inline int
-bt819_read (struct i2c_client *client,
- u8 reg)
+static inline int bt819_read(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
-static int
-bt819_init (struct i2c_client *client)
+static int bt819_init(struct i2c_client *client)
{
struct bt819 *decoder = i2c_get_clientdata(client);
static unsigned char init[] = {
- //0x1f, 0x00, /* Reset */
+ /*0x1f, 0x00,*/ /* Reset */
0x01, 0x59, /* 0x01 input format */
0x02, 0x00, /* 0x02 temporal decimation */
0x03, 0x12, /* 0x03 Cropping msb */
@@ -218,12 +181,10 @@ bt819_init (struct i2c_client *client)
struct timing *timing = &timing_data[decoder->norm];
init[0x03 * 2 - 1] =
- (((timing->vdelay >> 8) & 0x03) << 6) | (((timing->
- vactive >> 8) &
- 0x03) << 4) |
- (((timing->hdelay >> 8) & 0x03) << 2) | ((timing->
- hactive >> 8) &
- 0x03);
+ (((timing->vdelay >> 8) & 0x03) << 6) |
+ (((timing->vactive >> 8) & 0x03) << 4) |
+ (((timing->hdelay >> 8) & 0x03) << 2) |
+ ((timing->hactive >> 8) & 0x03);
init[0x04 * 2 - 1] = timing->vdelay & 0xff;
init[0x05 * 2 - 1] = timing->vactive & 0xff;
init[0x06 * 2 - 1] = timing->hdelay & 0xff;
@@ -238,27 +199,22 @@ bt819_init (struct i2c_client *client)
/* init */
return bt819_write_block(client, init, sizeof(init));
-
}
/* ----------------------------------------------------------------------- */
-static int
-bt819_command (struct i2c_client *client,
- unsigned int cmd,
- void *arg)
+static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg)
{
int temp;
struct bt819 *decoder = i2c_get_clientdata(client);
- if (!decoder->initialized) { // First call to bt819_init could be
- bt819_init(client); // without #FRST = 0
+ if (!decoder->initialized) { /* First call to bt819_init could be */
+ bt819_init(client); /* without #FRST = 0 */
decoder->initialized = 1;
}
switch (cmd) {
-
case 0:
/* This is just for testing!!! */
bt819_init(client);
@@ -274,8 +230,8 @@ bt819_command (struct i2c_client *client,
VIDEO_DECODER_CCIR;
cap->inputs = 8;
cap->outputs = 1;
- }
break;
+ }
case DECODER_GET_STATUS:
{
@@ -285,9 +241,9 @@ bt819_command (struct i2c_client *client,
status = bt819_read(client, 0x00);
res = 0;
- if ((status & 0x80)) {
+ if ((status & 0x80))
res |= DECODER_STATUS_GOOD;
- }
+
switch (decoder->norm) {
case VIDEO_MODE_NTSC:
res |= DECODER_STATUS_NTSC;
@@ -297,28 +253,25 @@ bt819_command (struct i2c_client *client,
break;
default:
case VIDEO_MODE_AUTO:
- if ((status & 0x10)) {
+ if ((status & 0x10))
res |= DECODER_STATUS_PAL;
- } else {
+ else
res |= DECODER_STATUS_NTSC;
- }
break;
}
res |= DECODER_STATUS_COLOR;
*iarg = res;
- dprintk(1, KERN_INFO "%s: get status %x\n", I2C_NAME(client),
- *iarg);
- }
+ v4l_dbg(1, debug, client, "get status %x\n", *iarg);
break;
+ }
case DECODER_SET_NORM:
{
int *iarg = arg;
struct timing *timing = NULL;
- dprintk(1, KERN_INFO "%s: set norm %x\n", I2C_NAME(client),
- *iarg);
+ v4l_dbg(1, debug, client, "set norm %x\n", *iarg);
switch (*iarg) {
case VIDEO_MODE_NTSC:
@@ -327,7 +280,7 @@ bt819_command (struct i2c_client *client,
bt819_setbit(client, 0x01, 5, 0);
bt819_write(client, 0x18, 0x68);
bt819_write(client, 0x19, 0x5d);
- //bt819_setbit(client, 0x1a, 5, 1);
+ /* bt819_setbit(client, 0x1a, 5, 1); */
timing = &timing_data[VIDEO_MODE_NTSC];
break;
case VIDEO_MODE_PAL:
@@ -336,7 +289,7 @@ bt819_command (struct i2c_client *client,
bt819_setbit(client, 0x01, 5, 1);
bt819_write(client, 0x18, 0x7f);
bt819_write(client, 0x19, 0x72);
- //bt819_setbit(client, 0x1a, 5, 0);
+ /* bt819_setbit(client, 0x1a, 5, 0); */
timing = &timing_data[VIDEO_MODE_PAL];
break;
case VIDEO_MODE_AUTO:
@@ -344,10 +297,7 @@ bt819_command (struct i2c_client *client,
bt819_setbit(client, 0x01, 1, 0);
break;
default:
- dprintk(1,
- KERN_ERR
- "%s: unsupported norm %d\n",
- I2C_NAME(client), *iarg);
+ v4l_dbg(1, debug, client, "unsupported norm %x\n", *iarg);
return -EINVAL;
}
@@ -366,19 +316,17 @@ bt819_command (struct i2c_client *client,
}
decoder->norm = *iarg;
- }
break;
+ }
case DECODER_SET_INPUT:
{
int *iarg = arg;
- dprintk(1, KERN_INFO "%s: set input %x\n", I2C_NAME(client),
- *iarg);
+ v4l_dbg(1, debug, client, "set input %x\n", *iarg);
- if (*iarg < 0 || *iarg > 7) {
+ if (*iarg < 0 || *iarg > 7)
return -EINVAL;
- }
if (decoder->input != *iarg) {
decoder->input = *iarg;
@@ -391,52 +339,42 @@ bt819_command (struct i2c_client *client,
bt819_setbit(client, 0x1a, 1, 0);
}
}
- }
break;
+ }
case DECODER_SET_OUTPUT:
{
int *iarg = arg;
- dprintk(1, KERN_INFO "%s: set output %x\n", I2C_NAME(client),
- *iarg);
+ v4l_dbg(1, debug, client, "set output %x\n", *iarg);
/* not much choice of outputs */
- if (*iarg != 0) {
+ if (*iarg != 0)
return -EINVAL;
- }
- }
break;
+ }
case DECODER_ENABLE_OUTPUT:
{
int *iarg = arg;
int enable = (*iarg != 0);
- dprintk(1, KERN_INFO "%s: enable output %x\n",
- I2C_NAME(client), *iarg);
+ v4l_dbg(1, debug, client, "enable output %x\n", *iarg);
if (decoder->enable != enable) {
decoder->enable = enable;
-
- if (decoder->enable) {
- bt819_setbit(client, 0x16, 7, 0);
- } else {
- bt819_setbit(client, 0x16, 7, 1);
- }
+ bt819_setbit(client, 0x16, 7, !enable);
}
- }
break;
+ }
case DECODER_SET_PICTURE:
{
struct video_picture *pic = arg;
- dprintk(1,
- KERN_INFO
- "%s: set picture brightness %d contrast %d colour %d\n",
- I2C_NAME(client), pic->brightness, pic->contrast,
- pic->colour);
+ v4l_dbg(1, debug, client,
+ "set picture brightness %d contrast %d colour %d\n",
+ pic->brightness, pic->contrast, pic->colour);
if (decoder->bright != pic->brightness) {
@@ -474,8 +412,8 @@ bt819_command (struct i2c_client *client,
bt819_write(client, 0x0f,
128 - (decoder->hue >> 8));
}
- }
break;
+ }
default:
return -EINVAL;
@@ -486,55 +424,44 @@ bt819_command (struct i2c_client *client,
/* ----------------------------------------------------------------------- */
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = {
- I2C_BT819 >> 1,
- 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 unsigned short normal_i2c[] = { 0x8a >> 1, I2C_CLIENT_END };
-static struct i2c_driver i2c_driver_bt819;
+I2C_CLIENT_INSMOD;
-static int
-bt819_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
+static int bt819_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int i, id;
+ int i, ver;
struct bt819 *decoder;
- struct i2c_client *client;
-
- dprintk(1,
- KERN_INFO
- "bt819: detecting bt819 client on address 0x%x\n",
- address << 1);
+ const char *name;
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return 0;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_bt819;
+ ver = bt819_read(client, 0x17);
+ switch (ver & 0xf0) {
+ case 0x70:
+ name = "bt819a";
+ break;
+ case 0x60:
+ name = "bt817a";
+ break;
+ case 0x20:
+ name = "bt815a";
+ break;
+ default:
+ v4l_dbg(1, debug, client,
+ "unknown chip version 0x%02x\n", ver);
+ return -ENODEV;
+ }
+
+ v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+ client->addr << 1, client->adapter->name);
decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
- if (decoder == NULL) {
- kfree(client);
+ if (decoder == NULL)
return -ENOMEM;
- }
decoder->norm = VIDEO_MODE_NTSC;
decoder->input = 0;
decoder->enable = 1;
@@ -545,97 +472,33 @@ bt819_detect_client (struct i2c_adapter *adapter,
decoder->initialized = 0;
i2c_set_clientdata(client, decoder);
- id = bt819_read(client, 0x17);
- switch (id & 0xf0) {
- case 0x70:
- strlcpy(I2C_NAME(client), "bt819a", sizeof(I2C_NAME(client)));
- break;
- case 0x60:
- strlcpy(I2C_NAME(client), "bt817a", sizeof(I2C_NAME(client)));
- break;
- case 0x20:
- strlcpy(I2C_NAME(client), "bt815a", sizeof(I2C_NAME(client)));
- break;
- default:
- dprintk(1,
- KERN_ERR
- "bt819: unknown chip version 0x%x (ver 0x%x)\n",
- id & 0xf0, id & 0x0f);
- kfree(decoder);
- kfree(client);
- return 0;
- }
-
- i = i2c_attach_client(client);
- if (i) {
- kfree(client);
- kfree(decoder);
- return i;
- }
-
i = bt819_init(client);
- if (i < 0) {
- dprintk(1, KERN_ERR "%s_attach: init status %d\n",
- I2C_NAME(client), i);
- } else {
- dprintk(1,
- KERN_INFO
- "%s_attach: chip version 0x%x at address 0x%x\n",
- I2C_NAME(client), id & 0x0f,
- client->addr << 1);
- }
-
+ if (i < 0)
+ v4l_dbg(1, debug, client, "init status %d\n", i);
return 0;
}
-static int
-bt819_attach_adapter (struct i2c_adapter *adapter)
-{
- return i2c_probe(adapter, &addr_data, &bt819_detect_client);
-}
-
-static int
-bt819_detach_client (struct i2c_client *client)
+static int bt819_remove(struct i2c_client *client)
{
- struct bt819 *decoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
-
- kfree(decoder);
- kfree(client);
-
+ kfree(i2c_get_clientdata(client));
return 0;
}
/* ----------------------------------------------------------------------- */
-static struct i2c_driver i2c_driver_bt819 = {
- .driver = {
- .name = "bt819",
- },
-
- .id = I2C_DRIVERID_BT819,
+static const struct i2c_device_id bt819_id[] = {
+ { "bt819a", 0 },
+ { "bt817a", 0 },
+ { "bt815a", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bt819_id);
- .attach_adapter = bt819_attach_adapter,
- .detach_client = bt819_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "bt819",
+ .driverid = I2C_DRIVERID_BT819,
.command = bt819_command,
+ .probe = bt819_probe,
+ .remove = bt819_remove,
+ .id_table = bt819_id,
};
-
-static int __init
-bt819_init_module (void)
-{
- return i2c_add_driver(&i2c_driver_bt819);
-}
-
-static void __exit
-bt819_exit (void)
-{
- i2c_del_driver(&i2c_driver_bt819);
-}
-
-module_init(bt819_init_module);
-module_exit(bt819_exit);
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index ab2ce4d7b5d..4213867507f 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -29,43 +29,24 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/video_encoder.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
#include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/videodev.h>
+#include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
MODULE_LICENSE("GPL");
-
-#define I2C_NAME(s) (s)->name
-
-
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
/* ----------------------------------------------------------------------- */
#define BT856_REG_OFFSET 0xDA
@@ -78,14 +59,9 @@ struct bt856 {
int enable;
};
-#define I2C_BT856 0x88
-
/* ----------------------------------------------------------------------- */
-static inline int
-bt856_write (struct i2c_client *client,
- u8 reg,
- u8 value)
+static inline int bt856_write(struct i2c_client *client, u8 reg, u8 value)
{
struct bt856 *encoder = i2c_get_clientdata(client);
@@ -93,46 +69,36 @@ bt856_write (struct i2c_client *client,
return i2c_smbus_write_byte_data(client, reg, value);
}
-static inline int
-bt856_setbit (struct i2c_client *client,
- u8 reg,
- u8 bit,
- u8 value)
+static inline int bt856_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
{
struct bt856 *encoder = i2c_get_clientdata(client);
return bt856_write(client, reg,
- (encoder->
- reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
- (value ? (1 << bit) : 0));
+ (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
+ (value ? (1 << bit) : 0));
}
-static void
-bt856_dump (struct i2c_client *client)
+static void bt856_dump(struct i2c_client *client)
{
int i;
struct bt856 *encoder = i2c_get_clientdata(client);
- printk(KERN_INFO "%s: register dump:", I2C_NAME(client));
+ v4l_info(client, "register dump:\n");
for (i = 0; i < BT856_NR_REG; i += 2)
- printk(" %02x", encoder->reg[i]);
- printk("\n");
+ printk(KERN_CONT " %02x", encoder->reg[i]);
+ printk(KERN_CONT "\n");
}
/* ----------------------------------------------------------------------- */
-static int
-bt856_command (struct i2c_client *client,
- unsigned int cmd,
- void *arg)
+static int bt856_command(struct i2c_client *client, unsigned cmd, void *arg)
{
struct bt856 *encoder = i2c_get_clientdata(client);
switch (cmd) {
-
case 0:
/* This is just for testing!!! */
- dprintk(1, KERN_INFO "bt856: init\n");
+ v4l_dbg(1, debug, client, "init\n");
bt856_write(client, 0xdc, 0x18);
bt856_write(client, 0xda, 0);
bt856_write(client, 0xde, 0);
@@ -142,7 +108,6 @@ bt856_command (struct i2c_client *client,
bt856_setbit(client, 0xdc, 4, 1);
switch (encoder->norm) {
-
case VIDEO_MODE_NTSC:
bt856_setbit(client, 0xdc, 2, 0);
break;
@@ -163,26 +128,23 @@ bt856_command (struct i2c_client *client,
{
struct video_encoder_capability *cap = arg;
- dprintk(1, KERN_INFO "%s: get capabilities\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "get capabilities\n");
cap->flags = VIDEO_ENCODER_PAL |
VIDEO_ENCODER_NTSC |
VIDEO_ENCODER_CCIR;
cap->inputs = 2;
cap->outputs = 1;
- }
break;
+ }
case ENCODER_SET_NORM:
{
int *iarg = arg;
- dprintk(1, KERN_INFO "%s: set norm %d\n", I2C_NAME(client),
- *iarg);
+ v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
switch (*iarg) {
-
case VIDEO_MODE_NTSC:
bt856_setbit(client, 0xdc, 2, 0);
break;
@@ -195,27 +157,23 @@ bt856_command (struct i2c_client *client,
default:
return -EINVAL;
-
}
encoder->norm = *iarg;
if (debug != 0)
bt856_dump(client);
- }
break;
+ }
case ENCODER_SET_INPUT:
{
int *iarg = arg;
- dprintk(1, KERN_INFO "%s: set input %d\n", I2C_NAME(client),
- *iarg);
+ v4l_dbg(1, debug, client, "set input %d\n", *iarg);
/* We only have video bus.
* iarg = 0: input is from bt819
* iarg = 1: input is from ZR36060 */
-
switch (*iarg) {
-
case 0:
bt856_setbit(client, 0xde, 4, 0);
bt856_setbit(client, 0xde, 3, 1);
@@ -234,27 +192,24 @@ bt856_command (struct i2c_client *client,
break;
default:
return -EINVAL;
-
}
if (debug != 0)
bt856_dump(client);
- }
break;
+ }
case ENCODER_SET_OUTPUT:
{
int *iarg = arg;
- dprintk(1, KERN_INFO "%s: set output %d\n", I2C_NAME(client),
- *iarg);
+ v4l_dbg(1, debug, client, "set output %d\n", *iarg);
/* not much choice of outputs */
- if (*iarg != 0) {
+ if (*iarg != 0)
return -EINVAL;
- }
- }
break;
+ }
case ENCODER_ENABLE_OUTPUT:
{
@@ -262,10 +217,9 @@ bt856_command (struct i2c_client *client,
encoder->enable = !!*iarg;
- dprintk(1, KERN_INFO "%s: enable output %d\n",
- I2C_NAME(client), encoder->enable);
- }
+ v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
break;
+ }
default:
return -EINVAL;
@@ -276,64 +230,29 @@ bt856_command (struct i2c_client *client,
/* ----------------------------------------------------------------------- */
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = { I2C_BT856 >> 1, 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 unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-static struct i2c_driver i2c_driver_bt856;
+I2C_CLIENT_INSMOD;
-static int
-bt856_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
+static int bt856_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int i;
- struct i2c_client *client;
struct bt856 *encoder;
- dprintk(1,
- KERN_INFO
- "bt856.c: detecting bt856 client on address 0x%x\n",
- address << 1);
-
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return 0;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_bt856;
- strlcpy(I2C_NAME(client), "bt856", sizeof(I2C_NAME(client)));
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
- if (encoder == NULL) {
- kfree(client);
+ if (encoder == NULL)
return -ENOMEM;
- }
encoder->norm = VIDEO_MODE_NTSC;
encoder->enable = 1;
i2c_set_clientdata(client, encoder);
- i = i2c_attach_client(client);
- if (i) {
- kfree(client);
- kfree(encoder);
- return i;
- }
-
bt856_write(client, 0xdc, 0x18);
bt856_write(client, 0xda, 0);
bt856_write(client, 0xde, 0);
@@ -359,65 +278,26 @@ bt856_detect_client (struct i2c_adapter *adapter,
if (debug != 0)
bt856_dump(client);
-
- dprintk(1, KERN_INFO "%s_attach: at address 0x%x\n", I2C_NAME(client),
- client->addr << 1);
-
return 0;
}
-static int
-bt856_attach_adapter (struct i2c_adapter *adapter)
+static int bt856_remove(struct i2c_client *client)
{
- dprintk(1,
- KERN_INFO
- "bt856.c: starting probe for adapter %s (0x%x)\n",
- I2C_NAME(adapter), adapter->id);
- return i2c_probe(adapter, &addr_data, &bt856_detect_client);
-}
-
-static int
-bt856_detach_client (struct i2c_client *client)
-{
- struct bt856 *encoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
-
- kfree(encoder);
- kfree(client);
-
+ kfree(i2c_get_clientdata(client));
return 0;
}
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver i2c_driver_bt856 = {
- .driver = {
- .name = "bt856",
- },
-
- .id = I2C_DRIVERID_BT856,
+static const struct i2c_device_id bt856_id[] = {
+ { "bt856", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bt856_id);
- .attach_adapter = bt856_attach_adapter,
- .detach_client = bt856_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "bt856",
+ .driverid = I2C_DRIVERID_BT856,
.command = bt856_command,
+ .probe = bt856_probe,
+ .remove = bt856_remove,
+ .id_table = bt856_id,
};
-
-static int __init
-bt856_init (void)
-{
- return i2c_add_driver(&i2c_driver_bt856);
-}
-
-static void __exit
-bt856_exit (void)
-{
- i2c_del_driver(&i2c_driver_bt856);
-}
-
-module_init(bt856_init);
-module_exit(bt856_exit);
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 96b415576f0..596f9e2376b 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -29,42 +29,28 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
#include <linux/i2c.h>
-
+#include <linux/i2c-id.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
-
#include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
+MODULE_AUTHOR("Mike Bernson & Dave Perks");
MODULE_LICENSE("GPL");
-#define BT866_DEVNAME "bt866"
-#define I2C_BT866 0x88
-
-MODULE_LICENSE("GPL");
-
-#define DEBUG(x) /* Debug driver */
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
/* ----------------------------------------------------------------------- */
struct bt866 {
- struct i2c_client *i2c;
- int addr;
- unsigned char reg[256];
+ u8 reg[256];
int norm;
int enable;
@@ -74,20 +60,45 @@ struct bt866 {
int sat;
};
-static int bt866_write(struct bt866 *dev,
- unsigned char subaddr, unsigned char data);
+static int bt866_write(struct i2c_client *client, u8 subaddr, u8 data)
+{
+ struct bt866 *encoder = i2c_get_clientdata(client);
+ u8 buffer[2];
+ int err;
+
+ buffer[0] = subaddr;
+ buffer[1] = data;
+
+ encoder->reg[subaddr] = data;
+
+ v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
+
+ for (err = 0; err < 3;) {
+ if (i2c_master_send(client, buffer, 2) == 2)
+ break;
+ err++;
+ v4l_warn(client, "error #%d writing to 0x%02x\n",
+ err, subaddr);
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+ }
+ if (err == 3) {
+ v4l_warn(client, "giving up\n");
+ return -1;
+ }
+
+ return 0;
+}
-static int bt866_do_command(struct bt866 *encoder,
- unsigned int cmd, void *arg)
+static int bt866_command(struct i2c_client *client, unsigned cmd, void *arg)
{
+ struct bt866 *encoder = i2c_get_clientdata(client);
+
switch (cmd) {
case ENCODER_GET_CAPABILITIES:
{
struct video_encoder_capability *cap = arg;
- DEBUG(printk
- (KERN_INFO "%s: get capabilities\n",
- encoder->i2c->name));
+ v4l_dbg(1, debug, client, "get capabilities\n");
cap->flags
= VIDEO_ENCODER_PAL
@@ -95,18 +106,16 @@ static int bt866_do_command(struct bt866 *encoder,
| VIDEO_ENCODER_CCIR;
cap->inputs = 2;
cap->outputs = 1;
+ break;
}
- break;
case ENCODER_SET_NORM:
{
int *iarg = arg;
- DEBUG(printk(KERN_INFO "%s: set norm %d\n",
- encoder->i2c->name, *iarg));
+ v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
switch (*iarg) {
-
case VIDEO_MODE_NTSC:
break;
@@ -115,11 +124,10 @@ static int bt866_do_command(struct bt866 *encoder,
default:
return -EINVAL;
-
}
encoder->norm = *iarg;
+ break;
}
- break;
case ENCODER_SET_INPUT:
{
@@ -155,7 +163,7 @@ static int bt866_do_command(struct bt866 *encoder,
u8 val;
for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
- bt866_write(encoder, init[i], init[i+1]);
+ bt866_write(client, init[i], init[i+1]);
val = encoder->reg[0xdc];
@@ -164,17 +172,16 @@ static int bt866_do_command(struct bt866 *encoder,
else
val &= ~0x40; /* !CBSWAP */
- bt866_write(encoder, 0xdc, val);
+ bt866_write(client, 0xdc, val);
val = encoder->reg[0xcc];
if (*iarg == 2)
val |= 0x01; /* OSDBAR */
else
val &= ~0x01; /* !OSDBAR */
- bt866_write(encoder, 0xcc, val);
+ bt866_write(client, 0xcc, val);
- DEBUG(printk(KERN_INFO "%s: set input %d\n",
- encoder->i2c->name, *iarg));
+ v4l_dbg(1, debug, client, "set input %d\n", *iarg);
switch (*iarg) {
case 0:
@@ -183,48 +190,44 @@ static int bt866_do_command(struct bt866 *encoder,
break;
default:
return -EINVAL;
-
}
+ break;
}
- break;
case ENCODER_SET_OUTPUT:
{
int *iarg = arg;
- DEBUG(printk(KERN_INFO "%s: set output %d\n",
- encoder->i2c->name, *iarg));
+ v4l_dbg(1, debug, client, "set output %d\n", *iarg);
/* not much choice of outputs */
if (*iarg != 0)
return -EINVAL;
+ break;
}
- break;
case ENCODER_ENABLE_OUTPUT:
{
int *iarg = arg;
encoder->enable = !!*iarg;
- DEBUG(printk
- (KERN_INFO "%s: enable output %d\n",
- encoder->i2c->name, encoder->enable));
+ v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
+ break;
}
- break;
case 4711:
{
int *iarg = arg;
__u8 val;
- printk("bt866: square = %d\n", *iarg);
+ v4l_dbg(1, debug, client, "square %d\n", *iarg);
val = encoder->reg[0xdc];
if (*iarg)
val |= 1; /* SQUARE */
else
val &= ~1; /* !SQUARE */
- bt866_write(encoder, 0xdc, val);
+ bt866_write(client, 0xdc, val);
break;
}
@@ -235,141 +238,49 @@ static int bt866_do_command(struct bt866 *encoder,
return 0;
}
-static int bt866_write(struct bt866 *encoder,
- unsigned char subaddr, unsigned char data)
-{
- unsigned char buffer[2];
- int err;
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
- buffer[0] = subaddr;
- buffer[1] = data;
-
- encoder->reg[subaddr] = data;
+I2C_CLIENT_INSMOD;
- DEBUG(printk
- ("%s: write 0x%02X = 0x%02X\n",
- encoder->i2c->name, subaddr, data));
-
- for (err = 0; err < 3;) {
- if (i2c_master_send(encoder->i2c, buffer, 2) == 2)
- break;
- err++;
- printk(KERN_WARNING "%s: I/O error #%d "
- "(write 0x%02x/0x%02x)\n",
- encoder->i2c->name, err, encoder->addr, subaddr);
- schedule_timeout_interruptible(msecs_to_jiffies(100));
- }
- if (err == 3) {
- printk(KERN_WARNING "%s: giving up\n",
- encoder->i2c->name);
- return -1;
- }
-
- return 0;
-}
-
-static int bt866_attach(struct i2c_adapter *adapter);
-static int bt866_detach(struct i2c_client *client);
-static int bt866_command(struct i2c_client *client,
- unsigned int cmd, void *arg);
-
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {I2C_BT866>>1, I2C_CLIENT_END};
-static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
-static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
-
-static struct i2c_client_address_data addr_data = {
- normal_i2c,
- probe,
- ignore,
-};
-
-static struct i2c_driver i2c_driver_bt866 = {
- .driver.name = BT866_DEVNAME,
- .id = I2C_DRIVERID_BT866,
- .attach_adapter = bt866_attach,
- .detach_client = bt866_detach,
- .command = bt866_command
-};
-
-
-static struct i2c_client bt866_client_tmpl =
-{
- .name = "(nil)",
- .addr = 0,
- .adapter = NULL,
- .driver = &i2c_driver_bt866,
-};
-
-static int bt866_found_proc(struct i2c_adapter *adapter,
- int addr, int kind)
+static int bt866_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct bt866 *encoder;
- struct i2c_client *client;
- client = kzalloc(sizeof(*client), GFP_KERNEL);
- if (client == NULL)
- return -ENOMEM;
- memcpy(client, &bt866_client_tmpl, sizeof(*client));
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
- if (encoder == NULL) {
- kfree(client);
+ if (encoder == NULL)
return -ENOMEM;
- }
i2c_set_clientdata(client, encoder);
- client->adapter = adapter;
- client->addr = addr;
- sprintf(client->name, "%s-%02x", BT866_DEVNAME, adapter->id);
-
- encoder->i2c = client;
- encoder->addr = addr;
- //encoder->encoder_type = ENCODER_TYPE_UNKNOWN;
-
- /* initialize */
-
- i2c_attach_client(client);
-
- return 0;
-}
-
-static int bt866_attach(struct i2c_adapter *adapter)
-{
- if (adapter->id == I2C_HW_B_ZR36067)
- return i2c_probe(adapter, &addr_data, bt866_found_proc);
- return 0;
-}
-
-static int bt866_detach(struct i2c_client *client)
-{
- struct bt866 *encoder = i2c_get_clientdata(client);
-
- i2c_detach_client(client);
- kfree(encoder);
- kfree(client);
-
return 0;
}
-static int bt866_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static int bt866_remove(struct i2c_client *client)
{
- struct bt866 *encoder = i2c_get_clientdata(client);
- return bt866_do_command(encoder, cmd, arg);
-}
-
-static int __devinit bt866_init(void)
-{
- i2c_add_driver(&i2c_driver_bt866);
+ kfree(i2c_get_clientdata(client));
return 0;
}
-static void __devexit bt866_exit(void)
+static int bt866_legacy_probe(struct i2c_adapter *adapter)
{
- i2c_del_driver(&i2c_driver_bt866);
+ return adapter->id == I2C_HW_B_ZR36067;
}
-module_init(bt866_init);
-module_exit(bt866_exit);
+static const struct i2c_device_id bt866_id[] = {
+ { "bt866", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bt866_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "bt866",
+ .driverid = I2C_DRIVERID_BT866,
+ .command = bt866_command,
+ .probe = bt866_probe,
+ .remove = bt866_remove,
+ .legacy_probe = bt866_legacy_probe,
+ .id_table = bt866_id,
+};
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 5858bf5ff41..9ec4cec2e52 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -4246,7 +4246,7 @@ static int __devinit bttv_register_video(struct bttv *btv)
video_nr[btv->c.nr]) < 0)
goto err;
printk(KERN_INFO "bttv%d: registered device video%d\n",
- btv->c.nr,btv->video_dev->minor & 0x1f);
+ btv->c.nr, btv->video_dev->num);
if (device_create_file(&btv->video_dev->dev,
&dev_attr_card)<0) {
printk(KERN_ERR "bttv%d: device_create_file 'card' "
@@ -4263,7 +4263,7 @@ static int __devinit bttv_register_video(struct bttv *btv)
vbi_nr[btv->c.nr]) < 0)
goto err;
printk(KERN_INFO "bttv%d: registered device vbi%d\n",
- btv->c.nr,btv->vbi_dev->minor & 0x1f);
+ btv->c.nr, btv->vbi_dev->num);
if (!btv->has_radio)
return 0;
@@ -4275,7 +4275,7 @@ static int __devinit bttv_register_video(struct bttv *btv)
radio_nr[btv->c.nr]) < 0)
goto err;
printk(KERN_INFO "bttv%d: registered device radio%d\n",
- btv->c.nr,btv->radio_dev->minor & 0x1f);
+ btv->c.nr, btv->radio_dev->num);
/* all done */
return 0;
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 17aa0adb346..0f930d35146 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -815,7 +815,7 @@ static int init_cqcam(struct parport *port)
}
printk(KERN_INFO "video%d: Colour QuickCam found on %s\n",
- qcam->vdev.minor, qcam->pport->name);
+ qcam->vdev.num, qcam->pport->name);
qcams[num_cams++] = qcam;
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index fc9497bdd32..a8c068e1de1 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -2059,10 +2059,10 @@ static void cafe_dfs_cam_setup(struct cafe_camera *cam)
if (!cafe_dfs_root)
return;
- sprintf(fname, "regs-%d", cam->v4ldev.minor);
+ sprintf(fname, "regs-%d", cam->v4ldev.num);
cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
cam, &cafe_dfs_reg_ops);
- sprintf(fname, "cam-%d", cam->v4ldev.minor);
+ sprintf(fname, "cam-%d", cam->v4ldev.num);
cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
cam, &cafe_dfs_cam_ops);
}
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 1798b779a25..16c094f7785 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -1347,7 +1347,7 @@ static void create_proc_cpia_cam(struct cam_data *cam)
if (!cpia_proc_root || !cam)
return;
- snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
+ snprintf(name, sizeof(name), "video%d", cam->vdev.num);
ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
if (!ent)
@@ -1372,7 +1372,7 @@ static void destroy_proc_cpia_cam(struct cam_data *cam)
if (!cam || !cam->proc_entry)
return;
- snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
+ snprintf(name, sizeof(name), "video%d", cam->vdev.num);
remove_proc_entry(name, cpia_proc_root);
cam->proc_entry = NULL;
}
@@ -4005,7 +4005,7 @@ void cpia_unregister_camera(struct cam_data *cam)
}
#ifdef CONFIG_PROC_FS
- DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
+ DBG("destroying /proc/cpia/video%d\n", cam->vdev.num);
destroy_proc_cpia_cam(cam);
#endif
if (!cam->open_count) {
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 897e8d1a5c3..1c6bd633f19 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -1973,7 +1973,7 @@ void cpia2_unregister_camera(struct camera_data *cam)
} else {
LOG("/dev/video%d removed while open, "
"deferring video_unregister_device\n",
- cam->vdev->minor);
+ cam->vdev->num);
}
}
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 085121c2b47..7a1a7830a6b 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -613,6 +613,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
const struct pci_device_id *pci_id)
{
int retval = 0;
+ int i;
int vbi_buf_size;
u32 devtype;
struct cx18 *cx;
@@ -698,7 +699,8 @@ static int __devinit cx18_probe(struct pci_dev *dev,
/* active i2c */
CX18_DEBUG_INFO("activating i2c...\n");
- if (init_cx18_i2c(cx)) {
+ retval = init_cx18_i2c(cx);
+ if (retval) {
CX18_ERR("Could not initialize i2c\n");
goto free_map;
}
@@ -836,8 +838,11 @@ err:
CX18_ERR("Error %d on initialization\n", retval);
cx18_log_statistics(cx);
- kfree(cx18_cards[cx18_cards_active]);
- cx18_cards[cx18_cards_active] = NULL;
+ i = cx->num;
+ spin_lock(&cx18_cards_lock);
+ kfree(cx18_cards[i]);
+ cx18_cards[i] = NULL;
+ spin_unlock(&cx18_cards_lock);
return retval;
}
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index fa8be0731a3..a4b1708fafe 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -41,6 +41,7 @@
#include <linux/pagemap.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
+#include <asm/byteorder.h>
#include <linux/dvb/video.h>
#include <linux/dvb/audio.h>
diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h
index 197d4fbd9f9..287a5e8bf67 100644
--- a/drivers/media/video/cx18/cx18-io.h
+++ b/drivers/media/video/cx18/cx18-io.h
@@ -39,7 +39,7 @@ static inline void cx18_io_delay(struct cx18 *cx)
/* Statistics gathering */
static inline
-void cx18_log_write_retries(struct cx18 *cx, int i, const void *addr)
+void cx18_log_write_retries(struct cx18 *cx, int i, const void __iomem *addr)
{
if (i > CX18_MAX_MMIO_RETRIES)
i = CX18_MAX_MMIO_RETRIES;
@@ -48,7 +48,7 @@ void cx18_log_write_retries(struct cx18 *cx, int i, const void *addr)
}
static inline
-void cx18_log_read_retries(struct cx18 *cx, int i, const void *addr)
+void cx18_log_read_retries(struct cx18 *cx, int i, const void __iomem *addr)
{
if (i > CX18_MAX_MMIO_RETRIES)
i = CX18_MAX_MMIO_RETRIES;
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 0c8e7542cf6..e5ff7705b7a 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -200,16 +200,18 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
/* Initialize v4l2 variables and register v4l2 devices */
int cx18_streams_setup(struct cx18 *cx)
{
- int type;
+ int type, ret;
/* Setup V4L2 Devices */
for (type = 0; type < CX18_MAX_STREAMS; type++) {
/* Prepare device */
- if (cx18_prep_dev(cx, type))
+ ret = cx18_prep_dev(cx, type);
+ if (ret < 0)
break;
/* Allocate Stream */
- if (cx18_stream_alloc(&cx->streams[type]))
+ ret = cx18_stream_alloc(&cx->streams[type]);
+ if (ret < 0)
break;
}
if (type == CX18_MAX_STREAMS)
@@ -217,14 +219,14 @@ int cx18_streams_setup(struct cx18 *cx)
/* One or more streams could not be initialized. Clean 'em all up. */
cx18_streams_cleanup(cx, 0);
- return -ENOMEM;
+ return ret;
}
static int cx18_reg_dev(struct cx18 *cx, int type)
{
struct cx18_stream *s = &cx->streams[type];
int vfl_type = cx18_stream_info[type].vfl_type;
- int num;
+ int num, ret;
/* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
* We need a VFL_TYPE_TS defined.
@@ -233,9 +235,10 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
/* just return if no DVB is supported */
if ((cx->card->hw_all & CX18_HW_DVB) == 0)
return 0;
- if (cx18_dvb_register(s) < 0) {
+ ret = cx18_dvb_register(s);
+ if (ret < 0) {
CX18_ERR("DVB failed to register\n");
- return -EINVAL;
+ return ret;
}
}
@@ -252,12 +255,13 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
}
/* Register device. First try the desired minor, then any free one. */
- if (video_register_device(s->v4l2dev, vfl_type, num)) {
+ ret = video_register_device(s->v4l2dev, vfl_type, num);
+ if (ret < 0) {
CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
s->name, num);
video_device_release(s->v4l2dev);
s->v4l2dev = NULL;
- return -ENOMEM;
+ return ret;
}
num = s->v4l2dev->num;
@@ -290,18 +294,22 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
int cx18_streams_register(struct cx18 *cx)
{
int type;
- int err = 0;
+ int err;
+ int ret = 0;
/* Register V4L2 devices */
- for (type = 0; type < CX18_MAX_STREAMS; type++)
- err |= cx18_reg_dev(cx, type);
+ for (type = 0; type < CX18_MAX_STREAMS; type++) {
+ err = cx18_reg_dev(cx, type);
+ if (err && ret == 0)
+ ret = err;
+ }
- if (err == 0)
+ if (ret == 0)
return 0;
/* One or more streams could not be initialized. Clean 'em all up. */
cx18_streams_cleanup(cx, 1);
- return -ENOMEM;
+ return ret;
}
/* Unregister v4l2 devices */
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index 395c11fa47c..00831f3ef8f 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -1815,7 +1815,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
cx23885_mc417_init(dev);
printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
- dev->name, dev->v4l_device->minor & 0x1f);
+ dev->name, dev->v4l_device->num);
return 0;
}
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 2cda15f829f..dac5ccc9ba7 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -39,16 +39,16 @@ struct cx23885_board cx23885_boards[] = {
.input = {{
.type = CX23885_VMUX_COMPOSITE1,
.vmux = 0,
- },{
+ }, {
.type = CX23885_VMUX_COMPOSITE2,
.vmux = 1,
- },{
+ }, {
.type = CX23885_VMUX_COMPOSITE3,
.vmux = 2,
- },{
+ }, {
.type = CX23885_VMUX_COMPOSITE4,
.vmux = 3,
- }},
+ } },
},
[CX23885_BOARD_HAUPPAUGE_HVR1800lp] = {
.name = "Hauppauge WinTV-HVR1800lp",
@@ -57,19 +57,19 @@ struct cx23885_board cx23885_boards[] = {
.type = CX23885_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xff00,
- },{
+ }, {
.type = CX23885_VMUX_DEBUG,
.vmux = 0,
.gpio0 = 0xff01,
- },{
+ }, {
.type = CX23885_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xff02,
- },{
+ }, {
.type = CX23885_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xff02,
- }},
+ } },
},
[CX23885_BOARD_HAUPPAUGE_HVR1800] = {
.name = "Hauppauge WinTV-HVR1800",
@@ -84,20 +84,20 @@ struct cx23885_board cx23885_boards[] = {
CX25840_VIN5_CH2 |
CX25840_VIN2_CH1,
.gpio0 = 0,
- },{
+ }, {
.type = CX23885_VMUX_COMPOSITE1,
.vmux = CX25840_VIN7_CH3 |
CX25840_VIN4_CH2 |
CX25840_VIN6_CH1,
.gpio0 = 0,
- },{
+ }, {
.type = CX23885_VMUX_SVIDEO,
.vmux = CX25840_VIN7_CH3 |
CX25840_VIN4_CH2 |
CX25840_VIN8_CH1 |
CX25840_SVIDEO_ON,
.gpio0 = 0,
- }},
+ } },
},
[CX23885_BOARD_HAUPPAUGE_HVR1250] = {
.name = "Hauppauge WinTV-HVR1250",
@@ -106,19 +106,19 @@ struct cx23885_board cx23885_boards[] = {
.type = CX23885_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xff00,
- },{
+ }, {
.type = CX23885_VMUX_DEBUG,
.vmux = 0,
.gpio0 = 0xff01,
- },{
+ }, {
.type = CX23885_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xff02,
- },{
+ }, {
.type = CX23885_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xff02,
- }},
+ } },
},
[CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = {
.name = "DViCO FusionHDTV5 Express",
@@ -169,43 +169,43 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x0070,
.subdevice = 0x3400,
.card = CX23885_BOARD_UNKNOWN,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x7600,
.card = CX23885_BOARD_HAUPPAUGE_HVR1800lp,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x7800,
.card = CX23885_BOARD_HAUPPAUGE_HVR1800,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x7801,
.card = CX23885_BOARD_HAUPPAUGE_HVR1800,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x7809,
.card = CX23885_BOARD_HAUPPAUGE_HVR1800,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x7911,
.card = CX23885_BOARD_HAUPPAUGE_HVR1250,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xd500,
.card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x7790,
.card = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x7797,
.card = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x7710,
.card = CX23885_BOARD_HAUPPAUGE_HVR1500,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x7717,
.card = CX23885_BOARD_HAUPPAUGE_HVR1500,
@@ -225,11 +225,11 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x0070,
.subdevice = 0x8010,
.card = CX23885_BOARD_HAUPPAUGE_HVR1400,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xd618,
.card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xdb78,
.card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP,
@@ -247,23 +247,25 @@ void cx23885_card_list(struct cx23885_dev *dev)
if (0 == dev->pci->subsystem_vendor &&
0 == dev->pci->subsystem_device) {
- printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n"
- "%s: be autodetected. Please pass card=<n> insmod option to\n"
- "%s: workaround that. Redirect complaints to the vendor of\n"
- "%s: the TV card. Best regards,\n"
+ printk(KERN_INFO
+ "%s: Board has no valid PCIe Subsystem ID and can't\n"
+ "%s: be autodetected. Pass card=<n> insmod option\n"
+ "%s: to workaround that. Redirect complaints to the\n"
+ "%s: vendor of the TV card. Best regards,\n"
"%s: -- tux\n",
dev->name, dev->name, dev->name, dev->name, dev->name);
} else {
- printk("%s: Your board isn't known (yet) to the driver. You can\n"
- "%s: try to pick one of the existing card configs via\n"
+ printk(KERN_INFO
+ "%s: Your board isn't known (yet) to the driver.\n"
+ "%s: Try to pick one of the existing card configs via\n"
"%s: card=<n> insmod option. Updating to the latest\n"
"%s: version might help as well.\n",
dev->name, dev->name, dev->name, dev->name);
}
- printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ printk(KERN_INFO "%s: Here is a list of valid choices for the card=<n> insmod option:\n",
dev->name);
for (i = 0; i < cx23885_bcount; i++)
- printk("%s: card=%d -> %s\n",
+ printk(KERN_INFO "%s: card=%d -> %s\n",
dev->name, i, cx23885_boards[i].name);
}
@@ -271,11 +273,11 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
{
struct tveeprom tv;
- tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data);
+ tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv,
+ eeprom_data);
/* Make sure we support the board model */
- switch (tv.model)
- {
+ switch (tv.model) {
case 71009:
/* WinTV-HVR1200 (PCIe, Retail, full height)
* DVB-T and basic analog */
@@ -303,21 +305,51 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
case 71999:
/* WinTV-HVR1200 (PCIe, OEM, full height)
* DVB-T and basic analog */
- case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
- case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */
- case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
- case 77041: /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM and Basic analog */
- case 77051: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */
- case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
- case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
- case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
- case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
- case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
- case 79001: /* WinTV-HVR1250 (PCIe, Retail, IR, full height, ATSC and Basic analog */
- case 79101: /* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */
- case 79561: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
- case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */
- case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
+ case 76601:
+ /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual
+ channel ATSC and MPEG2 HW Encoder */
+ case 77001:
+ /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC
+ and Basic analog */
+ case 77011:
+ /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC
+ and Basic analog */
+ case 77041:
+ /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM
+ and Basic analog */
+ case 77051:
+ /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM
+ and Basic analog */
+ case 78011:
+ /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 78501:
+ /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 78521:
+ /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 78531:
+ /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 78631:
+ /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 79001:
+ /* WinTV-HVR1250 (PCIe, Retail, IR, full height,
+ ATSC and Basic analog */
+ case 79101:
+ /* WinTV-HVR1250 (PCIe, Retail, IR, half height,
+ ATSC and Basic analog */
+ case 79561:
+ /* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
+ ATSC and Basic analog */
+ case 79571:
+ /* WinTV-HVR1250 (PCIe, OEM, No IR, full height,
+ ATSC and Basic analog */
+ case 79671:
+ /* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
+ ATSC and Basic analog */
case 80019:
/* WinTV-HVR1400 (Express Card, Retail, IR,
* DVB-T and Basic analog */
@@ -329,7 +361,8 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
* DVB-T and MPEG2 HW Encoder */
break;
default:
- printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
+ printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n",
+ dev->name, tv.model);
break;
}
@@ -352,7 +385,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
return -EINVAL;
}
- switch(dev->board) {
+ switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1400:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -383,7 +416,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
void cx23885_gpio_setup(struct cx23885_dev *dev)
{
- switch(dev->board) {
+ switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1250:
/* GPIO-0 cx24227 demodulator reset */
cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
@@ -617,10 +650,3 @@ void cx23885_card_setup(struct cx23885_dev *dev)
}
/* ------------------------------------------------------------------ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index beb3e61669a..8f6fb2add7d 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -37,12 +37,12 @@ MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
MODULE_LICENSE("GPL");
static unsigned int debug;
-module_param(debug,int,0644);
-MODULE_PARM_DESC(debug,"enable debug messages");
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
module_param_array(card, int, NULL, 0444);
-MODULE_PARM_DESC(card,"card type");
+MODULE_PARM_DESC(card, "card type");
#define dprintk(level, fmt, arg...)\
do { if (debug >= level)\
@@ -364,13 +364,12 @@ void cx23885_wakeup(struct cx23885_tsport *port,
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
}
- if (list_empty(&q->active)) {
+ if (list_empty(&q->active))
del_timer(&q->timeout);
- } else {
+ else
mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- }
if (bc != 1)
- printk("%s: %d buffers handled (should be 1)\n",
+ printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n",
__func__, bc);
}
@@ -381,8 +380,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
unsigned int i, lines;
u32 cdt;
- if (ch->cmds_start == 0)
- {
+ if (ch->cmds_start == 0) {
dprintk(1, "%s() Erasing channel [%s]\n", __func__,
ch->name);
cx_write(ch->ptr1_reg, 0);
@@ -418,15 +416,15 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
/* write CMDS */
if (ch->jumponly)
- cx_write(ch->cmds_start + 0, 8);
+ cx_write(ch->cmds_start + 0, 8);
else
- cx_write(ch->cmds_start + 0, risc);
+ cx_write(ch->cmds_start + 0, risc);
cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */
cx_write(ch->cmds_start + 8, cdt);
cx_write(ch->cmds_start + 12, (lines*16) >> 3);
cx_write(ch->cmds_start + 16, ch->ctrl_start);
if (ch->jumponly)
- cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) );
+ cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
else
cx_write(ch->cmds_start + 20, 64 >> 2);
for (i = 24; i < 80; i += 4)
@@ -436,9 +434,9 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
cx_write(ch->ptr1_reg, ch->fifo_start);
cx_write(ch->ptr2_reg, cdt);
cx_write(ch->cnt2_reg, (lines*16) >> 3);
- cx_write(ch->cnt1_reg, (bpl >> 3) -1);
+ cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
- dprintk(2,"[bridge %d] sram setup %s: bpl=%d lines=%d\n",
+ dprintk(2, "[bridge %d] sram setup %s: bpl=%d lines=%d\n",
dev->bridge,
ch->name,
bpl,
@@ -469,43 +467,43 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
u32 risc;
unsigned int i, j, n;
- printk("%s: %s - dma channel status dump\n",
+ printk(KERN_WARNING "%s: %s - dma channel status dump\n",
dev->name, ch->name);
for (i = 0; i < ARRAY_SIZE(name); i++)
- printk("%s: cmds: %-15s: 0x%08x\n",
+ printk(KERN_WARNING "%s: cmds: %-15s: 0x%08x\n",
dev->name, name[i],
cx_read(ch->cmds_start + 4*i));
for (i = 0; i < 4; i++) {
risc = cx_read(ch->cmds_start + 4 * (i + 14));
- printk("%s: risc%d: ", dev->name, i);
+ printk(KERN_WARNING "%s: risc%d: ", dev->name, i);
cx23885_risc_decode(risc);
}
for (i = 0; i < (64 >> 2); i += n) {
risc = cx_read(ch->ctrl_start + 4 * i);
/* No consideration for bits 63-32 */
- printk("%s: (0x%08x) iq %x: ", dev->name,
+ printk(KERN_WARNING "%s: (0x%08x) iq %x: ", dev->name,
ch->ctrl_start + 4 * i, i);
n = cx23885_risc_decode(risc);
for (j = 1; j < n; j++) {
risc = cx_read(ch->ctrl_start + 4 * (i + j));
- printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
+ printk(KERN_WARNING "%s: iq %x: 0x%08x [ arg #%d ]\n",
dev->name, i+j, risc, j);
}
}
- printk("%s: fifo: 0x%08x -> 0x%x\n",
+ printk(KERN_WARNING "%s: fifo: 0x%08x -> 0x%x\n",
dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
- printk("%s: ctrl: 0x%08x -> 0x%x\n",
+ printk(KERN_WARNING "%s: ctrl: 0x%08x -> 0x%x\n",
dev->name, ch->ctrl_start, ch->ctrl_start + 6*16);
- printk("%s: ptr1_reg: 0x%08x\n",
+ printk(KERN_WARNING "%s: ptr1_reg: 0x%08x\n",
dev->name, cx_read(ch->ptr1_reg));
- printk("%s: ptr2_reg: 0x%08x\n",
+ printk(KERN_WARNING "%s: ptr2_reg: 0x%08x\n",
dev->name, cx_read(ch->ptr2_reg));
- printk("%s: cnt1_reg: 0x%08x\n",
+ printk(KERN_WARNING "%s: cnt1_reg: 0x%08x\n",
dev->name, cx_read(ch->cnt1_reg));
- printk("%s: cnt2_reg: 0x%08x\n",
+ printk(KERN_WARNING "%s: cnt2_reg: 0x%08x\n",
dev->name, cx_read(ch->cnt2_reg));
}
@@ -515,13 +513,13 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port,
struct cx23885_dev *dev = port->dev;
unsigned int i, j, n;
- printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+ printk(KERN_INFO "%s: risc disasm: %p [dma=0x%08lx]\n",
dev->name, risc->cpu, (unsigned long)risc->dma);
for (i = 0; i < (risc->size >> 2); i += n) {
- printk("%s: %04d: ", dev->name, i);
+ printk(KERN_INFO "%s: %04d: ", dev->name, i);
n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i]));
for (j = 1; j < n; j++)
- printk("%s: %04d: 0x%08x [ arg #%d ]\n",
+ printk(KERN_INFO "%s: %04d: 0x%08x [ arg #%d ]\n",
dev->name, i + j, risc->cpu[i + j], j);
if (risc->cpu[i] == cpu_to_le32(RISC_JUMP))
break;
@@ -600,7 +598,7 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev)
* when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
* occur on the cx23887 bridge.
*/
- if(dev->bridge == CX23885_BRIDGE_885)
+ if (dev->bridge == CX23885_BRIDGE_885)
cx_clear(RDR_TLCTL0, 1 << 4);
return 0;
@@ -608,13 +606,13 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev)
static int get_resources(struct cx23885_dev *dev)
{
- if (request_mem_region(pci_resource_start(dev->pci,0),
- pci_resource_len(dev->pci,0),
+ if (request_mem_region(pci_resource_start(dev->pci, 0),
+ pci_resource_len(dev->pci, 0),
dev->name))
return 0;
printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
- dev->name, (unsigned long long)pci_resource_start(dev->pci,0));
+ dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
return -EBUSY;
}
@@ -623,7 +621,8 @@ static void cx23885_timeout(unsigned long data);
int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value);
-static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
+static int cx23885_init_tsport(struct cx23885_dev *dev,
+ struct cx23885_tsport *port, int portno)
{
dprintk(1, "%s(portno=%d)\n", __func__, portno);
@@ -643,7 +642,18 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p
port->mpegq.timeout.data = (unsigned long)port;
init_timer(&port->mpegq.timeout);
- switch(portno) {
+ mutex_init(&port->frontends.lock);
+ INIT_LIST_HEAD(&port->frontends.felist);
+ port->frontends.active_fe_id = 0;
+
+ /* This should be hardcoded allow a single frontend
+ * attachment to this tsport, keeping the -dvb.c
+ * code clean and safe.
+ */
+ if (!port->num_frontends)
+ port->num_frontends = 1;
+
+ switch (portno) {
case 1:
port->reg_gpcnt = VID_B_GPCNT;
port->reg_gpcnt_ctl = VID_B_GPCNT_CTL;
@@ -744,13 +754,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
mutex_unlock(&devlist);
/* Configure the internal memory */
- if(dev->pci->device == 0x8880) {
+ if (dev->pci->device == 0x8880) {
dev->bridge = CX23885_BRIDGE_887;
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 25000000;
dev->sram_channels = cx23887_sram_channels;
} else
- if(dev->pci->device == 0x8852) {
+ if (dev->pci->device == 0x8852) {
dev->bridge = CX23885_BRIDGE_885;
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 28000000;
@@ -831,8 +841,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
}
/* PCIe stuff */
- dev->lmmio = ioremap(pci_resource_start(dev->pci,0),
- pci_resource_len(dev->pci,0));
+ dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
+ pci_resource_len(dev->pci, 0));
dev->bmmio = (u8 __iomem *)dev->lmmio;
@@ -862,7 +872,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
cx23885_i2c_register(&dev->i2c_bus[1]);
cx23885_i2c_register(&dev->i2c_bus[2]);
cx23885_card_setup(dev);
- cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
+ cx23885_call_i2c_clients(&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
cx23885_ir_init(dev);
if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
@@ -908,8 +918,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
static void cx23885_dev_unregister(struct cx23885_dev *dev)
{
- release_mem_region(pci_resource_start(dev->pci,0),
- pci_resource_len(dev->pci,0));
+ release_mem_region(pci_resource_start(dev->pci, 0),
+ pci_resource_len(dev->pci, 0));
if (!atomic_dec_and_test(&dev->refcount))
return;
@@ -936,7 +946,7 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
iounmap(dev->lmmio);
}
-static __le32* cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
+static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
unsigned int lines)
@@ -957,31 +967,31 @@ static __le32* cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
}
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- *(rp++)=cpu_to_le32(0); /* bits 63-32 */
- offset+=bpl;
+ *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+ *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
+ *(rp++) = cpu_to_le32(0); /* bits 63-32 */
+ offset += bpl;
} else {
/* scanline needs to be split */
todo = bpl;
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+ *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|
(sg_dma_len(sg)-offset));
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
+ *(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= (sg_dma_len(sg)-offset);
offset = 0;
sg++;
while (todo > sg_dma_len(sg)) {
- *(rp++)=cpu_to_le32(RISC_WRITE|
+ *(rp++) = cpu_to_le32(RISC_WRITE|
sg_dma_len(sg));
- *(rp++)=cpu_to_le32(sg_dma_address(sg));
- *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ *(rp++) = cpu_to_le32(sg_dma_address(sg));
+ *(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= sg_dma_len(sg);
sg++;
}
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
- *(rp++)=cpu_to_le32(sg_dma_address(sg));
- *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+ *(rp++) = cpu_to_le32(sg_dma_address(sg));
+ *(rp++) = cpu_to_le32(0); /* bits 63-32 */
offset += todo;
}
offset += padding;
@@ -1010,9 +1020,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
/* write and jump need and extra dword */
- instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+ instructions = fields * (1 + ((bpl + padding) * lines)
+ / PAGE_SIZE + lines);
instructions += 2;
- if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+ rc = btcx_riscmem_alloc(pci, risc, instructions*12);
+ if (rc < 0)
return rc;
/* write risc instructions */
@@ -1026,7 +1038,7 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
/* save pointer to jmp instruction address */
risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
return 0;
}
@@ -1048,7 +1060,8 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
instructions += 1;
- if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+ rc = btcx_riscmem_alloc(pci, risc, instructions*12);
+ if (rc < 0)
return rc;
/* write risc instructions */
@@ -1057,7 +1070,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
/* save pointer to jmp instruction address */
risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
return 0;
}
@@ -1067,7 +1080,8 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
__le32 *rp;
int rc;
- if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
+ rc = btcx_riscmem_alloc(pci, risc, 4*16);
+ if (rc < 0)
return rc;
/* write risc instructions */
@@ -1161,22 +1175,23 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
/* setup fifo + format */
cx23885_sram_channel_setup(dev,
- &dev->sram_channels[ port->sram_chno ],
+ &dev->sram_channels[port->sram_chno],
port->ts_packet_size, buf->risc.dma);
- if(debug > 5) {
- cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] );
+ if (debug > 5) {
+ cx23885_sram_channel_dump(dev,
+ &dev->sram_channels[port->sram_chno]);
cx23885_risc_disasm(port, &buf->risc);
}
/* write TS length to chip */
cx_write(port->reg_lngth, buf->vb.width);
- if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
- (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) {
- printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n",
+ if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
+ (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
+ printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n",
__func__,
cx23885_boards[dev->board].portb,
- cx23885_boards[dev->board].portc );
+ cx23885_boards[dev->board].portc);
return -EINVAL;
}
@@ -1186,7 +1201,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
udelay(100);
/* If the port supports SRC SELECT, configure it */
- if(port->reg_src_sel)
+ if (port->reg_src_sel)
cx_write(port->reg_src_sel, port->src_sel_val);
cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val);
@@ -1195,7 +1210,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
udelay(100);
- // NOTE: this is 2 (reserved) for portb, does it matter?
+ /* NOTE: this is 2 (reserved) for portb, does it matter? */
/* reset counter to zero */
cx_write(port->reg_gpcnt_ctl, 3);
q->count = 1;
@@ -1229,11 +1244,11 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
cx_write(ALT_PIN_OUT_SEL, 0x10100045);
}
- switch(dev->bridge) {
+ switch (dev->bridge) {
case CX23885_BRIDGE_885:
case CX23885_BRIDGE_887:
/* enable irqs */
- dprintk(1, "%s() enabling TS int's and DMA\n", __func__ );
+ dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_set(port->reg_dma_ctl, port->dma_ctl_val);
cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask);
@@ -1292,8 +1307,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port,
struct cx23885_buffer *buf;
dprintk(5, "%s()\n", __func__);
- if (list_empty(&q->active))
- {
+ if (list_empty(&q->active)) {
struct cx23885_buffer *prev;
prev = NULL;
@@ -1311,7 +1325,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port,
buf->vb.state = VIDEOBUF_ACTIVE;
buf->count = q->count++;
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(5, "[%p/%d] restart_queue - first active\n",
+ dprintk(5, "[%p/%d] restart_queue - f/active\n",
buf, buf->vb.i);
} else if (prev->vb.width == buf->vb.width &&
@@ -1322,8 +1336,9 @@ int cx23885_restart_queue(struct cx23885_tsport *port,
buf->vb.state = VIDEOBUF_ACTIVE;
buf->count = q->count++;
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
- dprintk(5,"[%p/%d] restart_queue - move to active\n",
+ /* 64 bit bits 63-32 */
+ prev->risc.jmp[2] = cpu_to_le32(0);
+ dprintk(5, "[%p/%d] restart_queue - m/active\n",
buf, buf->vb.i);
} else {
return 0;
@@ -1362,7 +1377,8 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
buf->vb.size = size;
buf->vb.field = field /*V4L2_FIELD_TOP*/;
- if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
+ rc = videobuf_iolock(q, &buf->vb, NULL);
+ if (0 != rc)
goto fail;
cx23885_risc_databuffer(dev->pci, &buf->risc,
videobuf_to_dma(&buf->vb)->sglist,
@@ -1388,7 +1404,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
if (list_empty(&cx88q->active)) {
- dprintk( 1, "queue is empty - first active\n" );
+ dprintk(1, "queue is empty - first active\n");
list_add_tail(&buf->vb.queue, &cx88q->active);
cx23885_start_dma(port, cx88q, buf);
buf->vb.state = VIDEOBUF_ACTIVE;
@@ -1397,7 +1413,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
dprintk(1, "[%p/%d] %s - first active\n",
buf, buf->vb.i, __func__);
} else {
- dprintk( 1, "queue is not empty - append to active\n" );
+ dprintk(1, "queue is not empty - append to active\n");
prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
vb.queue);
list_add_tail(&buf->vb.queue, &cx88q->active);
@@ -1405,7 +1421,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
buf->count = cx88q->count++;
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
- dprintk( 1, "[%p/%d] %s - append to active\n",
+ dprintk(1, "[%p/%d] %s - append to active\n",
buf, buf->vb.i, __func__);
}
}
@@ -1431,7 +1447,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
}
if (restart) {
- dprintk(1, "restarting queue\n" );
+ dprintk(1, "restarting queue\n");
cx23885_restart_queue(port, q);
}
spin_unlock_irqrestore(&port->slock, flags);
@@ -1453,10 +1469,11 @@ static void cx23885_timeout(unsigned long data)
struct cx23885_tsport *port = (struct cx23885_tsport *)data;
struct cx23885_dev *dev = port->dev;
- dprintk(1, "%s()\n",__func__);
+ dprintk(1, "%s()\n", __func__);
if (debug > 5)
- cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+ cx23885_sram_channel_dump(dev,
+ &dev->sram_channels[port->sram_chno]);
cx23885_stop_dma(port);
do_cancel_buffers(port, "timeout", 1);
@@ -1532,16 +1549,23 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
if ((status & VID_BC_MSK_OPC_ERR) ||
(status & VID_BC_MSK_BAD_PKT) ||
(status & VID_BC_MSK_SYNC) ||
- (status & VID_BC_MSK_OF))
- {
+ (status & VID_BC_MSK_OF)) {
+
if (status & VID_BC_MSK_OPC_ERR)
- dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR);
+ dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n",
+ VID_BC_MSK_OPC_ERR);
+
if (status & VID_BC_MSK_BAD_PKT)
- dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", VID_BC_MSK_BAD_PKT);
+ dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n",
+ VID_BC_MSK_BAD_PKT);
+
if (status & VID_BC_MSK_SYNC)
- dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", VID_BC_MSK_SYNC);
+ dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n",
+ VID_BC_MSK_SYNC);
+
if (status & VID_BC_MSK_OF)
- dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", VID_BC_MSK_OF);
+ dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n",
+ VID_BC_MSK_OF);
printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name);
@@ -1595,7 +1619,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
ts2_status = cx_read(VID_C_INT_STAT);
ts2_mask = cx_read(VID_C_INT_MSK);
- if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) )
+ if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0))
goto out;
vida_count = cx_read(VID_A_GPCNT);
@@ -1610,38 +1634,56 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n",
ts2_status, ts2_mask, ts2_count);
- if ( (pci_status & PCI_MSK_RISC_RD) ||
- (pci_status & PCI_MSK_RISC_WR) ||
- (pci_status & PCI_MSK_AL_RD) ||
- (pci_status & PCI_MSK_AL_WR) ||
- (pci_status & PCI_MSK_APB_DMA) ||
- (pci_status & PCI_MSK_VID_C) ||
- (pci_status & PCI_MSK_VID_B) ||
- (pci_status & PCI_MSK_VID_A) ||
- (pci_status & PCI_MSK_AUD_INT) ||
- (pci_status & PCI_MSK_AUD_EXT) )
- {
+ if ((pci_status & PCI_MSK_RISC_RD) ||
+ (pci_status & PCI_MSK_RISC_WR) ||
+ (pci_status & PCI_MSK_AL_RD) ||
+ (pci_status & PCI_MSK_AL_WR) ||
+ (pci_status & PCI_MSK_APB_DMA) ||
+ (pci_status & PCI_MSK_VID_C) ||
+ (pci_status & PCI_MSK_VID_B) ||
+ (pci_status & PCI_MSK_VID_A) ||
+ (pci_status & PCI_MSK_AUD_INT) ||
+ (pci_status & PCI_MSK_AUD_EXT)) {
if (pci_status & PCI_MSK_RISC_RD)
- dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", PCI_MSK_RISC_RD);
+ dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
+ PCI_MSK_RISC_RD);
+
if (pci_status & PCI_MSK_RISC_WR)
- dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", PCI_MSK_RISC_WR);
+ dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n",
+ PCI_MSK_RISC_WR);
+
if (pci_status & PCI_MSK_AL_RD)
- dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", PCI_MSK_AL_RD);
+ dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n",
+ PCI_MSK_AL_RD);
+
if (pci_status & PCI_MSK_AL_WR)
- dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", PCI_MSK_AL_WR);
+ dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n",
+ PCI_MSK_AL_WR);
+
if (pci_status & PCI_MSK_APB_DMA)
- dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", PCI_MSK_APB_DMA);
+ dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n",
+ PCI_MSK_APB_DMA);
+
if (pci_status & PCI_MSK_VID_C)
- dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", PCI_MSK_VID_C);
+ dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n",
+ PCI_MSK_VID_C);
+
if (pci_status & PCI_MSK_VID_B)
- dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", PCI_MSK_VID_B);
+ dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n",
+ PCI_MSK_VID_B);
+
if (pci_status & PCI_MSK_VID_A)
- dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", PCI_MSK_VID_A);
+ dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n",
+ PCI_MSK_VID_A);
+
if (pci_status & PCI_MSK_AUD_INT)
- dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", PCI_MSK_AUD_INT);
+ dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n",
+ PCI_MSK_AUD_INT);
+
if (pci_status & PCI_MSK_AUD_EXT)
- dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", PCI_MSK_AUD_EXT);
+ dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n",
+ PCI_MSK_AUD_EXT);
}
@@ -1753,13 +1795,13 @@ static struct pci_device_id cx23885_pci_tbl[] = {
.device = 0x8852,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- },{
+ }, {
/* CX23887 Rev 2 */
.vendor = 0x14f1,
.device = 0x8880,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- },{
+ }, {
/* --- end of list --- */
}
};
@@ -1797,9 +1839,3 @@ module_init(cx23885_init);
module_exit(cx23885_fini);
/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 24bd18327aa..e1aac07b315 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -78,19 +78,19 @@ static int dvb_buf_prepare(struct videobuf_queue *q,
struct videobuf_buffer *vb, enum v4l2_field field)
{
struct cx23885_tsport *port = q->priv_data;
- return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb, field);
+ return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
}
static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
struct cx23885_tsport *port = q->priv_data;
- cx23885_buf_queue(port, (struct cx23885_buffer*)vb);
+ cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
}
static void dvb_buf_release(struct videobuf_queue *q,
struct videobuf_buffer *vb)
{
- cx23885_free_buffer(q, (struct cx23885_buffer*)vb);
+ cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
}
static struct videobuf_queue_ops dvb_qops = {
@@ -312,19 +312,25 @@ static int dvb_register(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
struct cx23885_i2c *i2c_bus = NULL;
+ struct videobuf_dvb_frontend *fe0;
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
/* init struct videobuf_dvb */
- port->dvb.name = dev->name;
+ fe0->dvb.name = dev->name;
/* init frontend */
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1250:
i2c_bus = &dev->i2c_bus[0];
- port->dvb.frontend = dvb_attach(s5h1409_attach,
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_generic_config,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend != NULL) {
- dvb_attach(mt2131_attach, port->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&hauppauge_generic_tunerconfig, 0);
}
@@ -333,27 +339,27 @@ static int dvb_register(struct cx23885_tsport *port)
i2c_bus = &dev->i2c_bus[0];
switch (alt_tuner) {
case 1:
- port->dvb.frontend =
+ fe0->dvb.frontend =
dvb_attach(s5h1409_attach,
&hauppauge_ezqam_config,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend != NULL) {
- dvb_attach(tda829x_attach, port->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
&dev->i2c_bus[1].i2c_adap, 0x42,
&tda829x_no_probe);
- dvb_attach(tda18271_attach, port->dvb.frontend,
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
0x60, &dev->i2c_bus[1].i2c_adap,
&hauppauge_tda18271_config);
}
break;
case 0:
default:
- port->dvb.frontend =
+ fe0->dvb.frontend =
dvb_attach(s5h1409_attach,
&hauppauge_generic_config,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend != NULL)
- dvb_attach(mt2131_attach, port->dvb.frontend,
+ if (fe0->dvb.frontend != NULL)
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&hauppauge_generic_tunerconfig, 0);
break;
@@ -361,42 +367,42 @@ static int dvb_register(struct cx23885_tsport *port)
break;
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
i2c_bus = &dev->i2c_bus[0];
- port->dvb.frontend = dvb_attach(s5h1409_attach,
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1800lp_config,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend != NULL) {
- dvb_attach(mt2131_attach, port->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&hauppauge_generic_tunerconfig, 0);
}
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
i2c_bus = &dev->i2c_bus[0];
- port->dvb.frontend = dvb_attach(lgdt330x_attach,
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_5_express,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, port->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap, 0x61,
TUNER_LG_TDVS_H06XF);
}
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
i2c_bus = &dev->i2c_bus[1];
- port->dvb.frontend = dvb_attach(s5h1409_attach,
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1500q_config,
&dev->i2c_bus[0].i2c_adap);
- if (port->dvb.frontend != NULL)
- dvb_attach(xc5000_attach, port->dvb.frontend,
+ if (fe0->dvb.frontend != NULL)
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&hauppauge_hvr1500q_tunerconfig);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500:
i2c_bus = &dev->i2c_bus[1];
- port->dvb.frontend = dvb_attach(s5h1409_attach,
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1500_config,
&dev->i2c_bus[0].i2c_adap);
- if (port->dvb.frontend != NULL) {
+ if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &i2c_bus->i2c_adap,
@@ -409,7 +415,7 @@ static int dvb_register(struct cx23885_tsport *port)
};
fe = dvb_attach(xc2028_attach,
- port->dvb.frontend, &cfg);
+ fe0->dvb.frontend, &cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
}
@@ -417,24 +423,24 @@ static int dvb_register(struct cx23885_tsport *port)
case CX23885_BOARD_HAUPPAUGE_HVR1200:
case CX23885_BOARD_HAUPPAUGE_HVR1700:
i2c_bus = &dev->i2c_bus[0];
- port->dvb.frontend = dvb_attach(tda10048_attach,
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
&hauppauge_hvr1200_config,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend != NULL) {
- dvb_attach(tda829x_attach, port->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
&dev->i2c_bus[1].i2c_adap, 0x42,
&tda829x_no_probe);
- dvb_attach(tda18271_attach, port->dvb.frontend,
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
0x60, &dev->i2c_bus[1].i2c_adap,
&hauppauge_hvr1200_tuner_config);
}
break;
case CX23885_BOARD_HAUPPAUGE_HVR1400:
i2c_bus = &dev->i2c_bus[0];
- port->dvb.frontend = dvb_attach(dib7000p_attach,
+ fe0->dvb.frontend = dvb_attach(dib7000p_attach,
&i2c_bus->i2c_adap,
0x12, &hauppauge_hvr1400_dib7000_config);
- if (port->dvb.frontend != NULL) {
+ if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &dev->i2c_bus[1].i2c_adap,
@@ -444,12 +450,13 @@ static int dvb_register(struct cx23885_tsport *port)
.fname = XC3028L_DEFAULT_FIRMWARE,
.max_len = 64,
.demod = 5000,
- /* This is true for all demods with v36 firmware? */
+ /* This is true for all demods with
+ v36 firmware? */
.type = XC2028_D2633,
};
fe = dvb_attach(xc2028_attach,
- port->dvb.frontend, &cfg);
+ fe0->dvb.frontend, &cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
}
@@ -457,25 +464,25 @@ static int dvb_register(struct cx23885_tsport *port)
case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
i2c_bus = &dev->i2c_bus[port->nr - 1];
- port->dvb.frontend = dvb_attach(s5h1409_attach,
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&dvico_s5h1409_config,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend == NULL)
- port->dvb.frontend = dvb_attach(s5h1411_attach,
+ if (fe0->dvb.frontend == NULL)
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
&dvico_s5h1411_config,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend != NULL)
- dvb_attach(xc5000_attach, port->dvb.frontend,
+ if (fe0->dvb.frontend != NULL)
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&dvico_xc5000_tunerconfig);
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
i2c_bus = &dev->i2c_bus[port->nr - 1];
- port->dvb.frontend = dvb_attach(zl10353_attach,
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_xc3028,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend != NULL) {
+ if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &i2c_bus->i2c_adap,
@@ -487,7 +494,7 @@ static int dvb_register(struct cx23885_tsport *port)
.demod = XC3028_FE_ZARLINK456,
};
- fe = dvb_attach(xc2028_attach, port->dvb.frontend,
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
&cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
@@ -497,10 +504,10 @@ static int dvb_register(struct cx23885_tsport *port)
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
i2c_bus = &dev->i2c_bus[0];
- port->dvb.frontend = dvb_attach(zl10353_attach,
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_xc3028,
&i2c_bus->i2c_adap);
- if (port->dvb.frontend != NULL) {
+ if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &dev->i2c_bus[1].i2c_adap,
@@ -512,73 +519,108 @@ static int dvb_register(struct cx23885_tsport *port)
.demod = XC3028_FE_ZARLINK456,
};
- fe = dvb_attach(xc2028_attach, port->dvb.frontend,
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
&cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
}
break;
default:
- printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+ printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
+ " isn't supported yet\n",
dev->name);
break;
}
- if (NULL == port->dvb.frontend) {
- printk("%s: frontend initialization failed\n", dev->name);
+ if (NULL == fe0->dvb.frontend) {
+ printk(KERN_ERR "%s: frontend initialization failed\n",
+ dev->name);
return -1;
}
/* define general-purpose callback pointer */
- port->dvb.frontend->callback = cx23885_tuner_callback;
+ fe0->dvb.frontend->callback = cx23885_tuner_callback;
/* Put the analog decoder in standby to keep it quiet */
cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
- if (port->dvb.frontend->ops.analog_ops.standby)
- port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend);
+ if (fe0->dvb.frontend->ops.analog_ops.standby)
+ fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
/* register everything */
- return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
- &dev->pci->dev, adapter_nr);
+ return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+ &dev->pci->dev, adapter_nr, 0);
+
}
int cx23885_dvb_register(struct cx23885_tsport *port)
{
+
+ struct videobuf_dvb_frontend *fe0;
struct cx23885_dev *dev = port->dev;
- int err;
+ int err, i;
+
+ /* Here we need to allocate the correct number of frontends,
+ * as reflected in the cards struct. The reality is that currrently
+ * no cx23885 boards support this - yet. But, if we don't modify this
+ * code then the second frontend would never be allocated (later)
+ * and fail with error before the attach in dvb_register().
+ * Without these changes we risk an OOPS later. The changes here
+ * are for safety, and should provide a good foundation for the
+ * future addition of any multi-frontend cx23885 based boards.
+ */
+ printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
+ port->num_frontends);
+
+ for (i = 1; i <= port->num_frontends; i++) {
+ if (videobuf_dvb_alloc_frontend(
+ &port->frontends, i) == NULL) {
+ printk(KERN_ERR "%s() failed to alloc\n", __func__);
+ return -ENOMEM;
+ }
- dprintk(1, "%s\n", __func__);
- dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
- dev->board,
- dev->name,
- dev->pci_bus,
- dev->pci_slot);
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
+ if (!fe0)
+ err = -EINVAL;
- err = -ENODEV;
+ dprintk(1, "%s\n", __func__);
+ dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n",
+ dev->board,
+ dev->name,
+ dev->pci_bus,
+ dev->pci_slot);
- /* dvb stuff */
- printk("%s: cx23885 based dvb card\n", dev->name);
- videobuf_queue_sg_init(&port->dvb.dvbq, &dvb_qops, &dev->pci->dev, &port->slock,
+ err = -ENODEV;
+
+ /* dvb stuff */
+ /* We have to init the queue for each frontend on a port. */
+ printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
+ videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
+ &dev->pci->dev, &port->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
sizeof(struct cx23885_buffer), port);
+ }
err = dvb_register(port);
if (err != 0)
- printk("%s() dvb_register failed err = %d\n", __func__, err);
+ printk(KERN_ERR "%s() dvb_register failed err = %d\n",
+ __func__, err);
return err;
}
int cx23885_dvb_unregister(struct cx23885_tsport *port)
{
- /* dvb */
- if(port->dvb.frontend)
- videobuf_dvb_unregister(&port->dvb);
+ struct videobuf_dvb_frontend *fe0;
+
+ /* FIXME: in an error condition where the we have
+ * an expected number of frontends (attach problem)
+ * then this might not clean up correctly, if 1
+ * is invalid.
+ * This comment only applies to future boards IF they
+ * implement MFE support.
+ */
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+ if (fe0->dvb.frontend)
+ videobuf_dvb_unregister_bus(&port->frontends);
return 0;
}
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
-*/
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index f98e476e961..bb7f71a1fcb 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -131,7 +131,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
printk(" >\n");
}
- for (cnt = 1; cnt < msg->len; cnt++ ) {
+ for (cnt = 1; cnt < msg->len; cnt++) {
/* following bytes */
wdata = msg->buf[cnt];
ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
@@ -151,9 +151,9 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
if (retval == 0)
goto eio;
if (i2c_debug) {
- printk(" %02x", msg->buf[cnt]);
+ dprintk(1, " %02x", msg->buf[cnt]);
if (!(ctrl & I2C_NOSTOP))
- printk(" >\n");
+ dprintk(1, " >\n");
}
}
return msg->len;
@@ -162,7 +162,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
retval = -EIO;
err:
if (i2c_debug)
- printk(" ERR: %d\n", retval);
+ printk(KERN_ERR " ERR: %d\n", retval);
return retval;
}
@@ -194,12 +194,12 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
if (i2c_debug) {
if (joined)
- printk(" R");
+ dprintk(1, " R");
else
- printk(" <R %02x", (msg->addr << 1) + 1);
+ dprintk(1, " <R %02x", (msg->addr << 1) + 1);
}
- for(cnt = 0; cnt < msg->len; cnt++) {
+ for (cnt = 0; cnt < msg->len; cnt++) {
ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
@@ -216,9 +216,9 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
goto eio;
msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
if (i2c_debug) {
- printk(" %02x", msg->buf[cnt]);
+ dprintk(1, " %02x", msg->buf[cnt]);
if (!(ctrl & I2C_NOSTOP))
- printk(" >\n");
+ dprintk(1, " >\n");
}
}
return msg->len;
@@ -227,7 +227,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
retval = -EIO;
err:
if (i2c_debug)
- printk(" ERR: %d\n", retval);
+ printk(KERN_ERR " ERR: %d\n", retval);
return retval;
}
@@ -353,17 +353,17 @@ static struct i2c_client cx23885_i2c_client_template = {
};
static char *i2c_devs[128] = {
- [0x10 >> 1] = "tda10048",
- [0x12 >> 1] = "dib7000pc",
- [ 0x1c >> 1 ] = "lgdt3303",
- [ 0x86 >> 1 ] = "tda9887",
- [ 0x32 >> 1 ] = "cx24227",
- [ 0x88 >> 1 ] = "cx25837",
- [ 0x84 >> 1 ] = "tda8295",
- [ 0xa0 >> 1 ] = "eeprom",
- [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
+ [0x10 >> 1] = "tda10048",
+ [0x12 >> 1] = "dib7000pc",
+ [0x1c >> 1] = "lgdt3303",
+ [0x86 >> 1] = "tda9887",
+ [0x32 >> 1] = "cx24227",
+ [0x88 >> 1] = "cx25837",
+ [0x84 >> 1] = "tda8295",
+ [0xa0 >> 1] = "eeprom",
+ [0xc0 >> 1] = "tuner/mt2131/tda8275",
[0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028",
- [0xc8 >> 1] = "tuner/xc3028L",
+ [0xc8 >> 1] = "tuner/xc3028L",
};
static void do_i2c_scan(char *name, struct i2c_client *c)
@@ -376,7 +376,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
rc = i2c_master_recv(c, &buf, 0);
if (rc < 0)
continue;
- printk("%s: i2c scan: found device @ 0x%x [%s]\n",
+ printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n",
name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
}
}
@@ -408,11 +408,12 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
bus->i2c_client.adapter = &bus->i2c_adap;
if (0 == bus->i2c_rc) {
- printk("%s: i2c bus %d registered\n", dev->name, bus->nr);
+ dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr);
if (i2c_scan)
do_i2c_scan(dev->name, &bus->i2c_client);
} else
- printk("%s: i2c bus %d register FAILED\n", dev->name, bus->nr);
+ printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
+ dev->name, bus->nr);
return bus->i2c_rc;
}
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index f75ed1c9b71..c742a10be5c 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -285,11 +285,10 @@ static void cx23885_video_wakeup(struct cx23885_dev *dev,
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
}
- if (list_empty(&q->active)) {
+ if (list_empty(&q->active))
del_timer(&q->timeout);
- } else {
+ else
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- }
if (bc != 1)
printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
__func__, bc);
@@ -379,12 +378,12 @@ static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
static int res_check(struct cx23885_fh *fh, unsigned int bit)
{
- return (fh->resources & bit);
+ return fh->resources & bit;
}
static int res_locked(struct cx23885_dev *dev, unsigned int bit)
{
- return (dev->resources & bit);
+ return dev->resources & bit;
}
static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
@@ -887,14 +886,16 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma)
/* ------------------------------------------------------------------ */
/* VIDEO CTRL IOCTLS */
-static int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+static int cx23885_get_control(struct cx23885_dev *dev,
+ struct v4l2_control *ctl)
{
dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
return 0;
}
-static int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+static int cx23885_set_control(struct cx23885_dev *dev,
+ struct v4l2_control *ctl)
{
dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
" (disabled - no action)\n", __func__);
@@ -1073,29 +1074,29 @@ static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
struct cx23885_fh *fh = priv;
- return (videobuf_reqbufs(get_queue(fh), p));
+ return videobuf_reqbufs(get_queue(fh), p);
}
static int vidioc_querybuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
struct cx23885_fh *fh = priv;
- return (videobuf_querybuf(get_queue(fh), p));
+ return videobuf_querybuf(get_queue(fh), p);
}
static int vidioc_qbuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
struct cx23885_fh *fh = priv;
- return (videobuf_qbuf(get_queue(fh), p));
+ return videobuf_qbuf(get_queue(fh), p);
}
static int vidioc_dqbuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
struct cx23885_fh *fh = priv;
- return (videobuf_dqbuf(get_queue(fh), p,
- file->f_flags & O_NONBLOCK));
+ return videobuf_dqbuf(get_queue(fh), p,
+ file->f_flags & O_NONBLOCK);
}
static int vidioc_streamon(struct file *file, void *priv,
@@ -1542,7 +1543,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
goto fail_unreg;
}
printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n",
- dev->name, dev->video_dev->minor & 0x1f);
+ dev->name, dev->video_dev->num);
/* initial device configuration */
mutex_lock(&dev->lock);
cx23885_set_tvnorm(dev, dev->tvnorm);
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index ba4e0aaed46..1d53f54cd94 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -37,7 +37,7 @@
#include <linux/version.h>
#include <linux/mutex.h>
-#define CX23885_VERSION_CODE KERNEL_VERSION(0,0,1)
+#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 1)
#define UNSET (-1U)
@@ -225,7 +225,7 @@ struct cx23885_tsport {
int nr;
int sram_chno;
- struct videobuf_dvb dvb;
+ struct videobuf_dvb_frontends frontends;
/* dma queues */
struct cx23885_dmaqueue mpegq;
@@ -262,6 +262,9 @@ struct cx23885_tsport {
u32 src_sel_val;
u32 vld_misc_val;
u32 hw_sop_ctrl_val;
+
+ /* Allow a single tsport to have multiple frontends */
+ u32 num_frontends;
};
struct cx23885_dev {
@@ -367,14 +370,14 @@ struct sram_channel {
/* ----------------------------------------------------------- */
#define cx_read(reg) readl(dev->lmmio + ((reg)>>2))
-#define cx_write(reg,value) writel((value), dev->lmmio + ((reg)>>2))
+#define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2))
-#define cx_andor(reg,mask,value) \
+#define cx_andor(reg, mask, value) \
writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
((value) & (mask)), dev->lmmio+((reg)>>2))
-#define cx_set(reg,bit) cx_andor((reg),(bit),(bit))
-#define cx_clear(reg,bit) cx_andor((reg),(bit),0)
+#define cx_set(reg, bit) cx_andor((reg), (bit), (bit))
+#define cx_clear(reg, bit) cx_andor((reg), (bit), 0)
/* ----------------------------------------------------------- */
/* cx23885-core.c */
@@ -411,7 +414,8 @@ extern const unsigned int cx23885_bcount;
extern struct cx23885_subid cx23885_subids[];
extern const unsigned int cx23885_idcount;
-extern int cx23885_tuner_callback(void *priv, int component, int command, int arg);
+extern int cx23885_tuner_callback(void *priv, int component,
+ int command, int arg);
extern void cx23885_card_list(struct cx23885_dev *dev);
extern int cx23885_ir_init(struct cx23885_dev *dev);
extern void cx23885_gpio_setup(struct cx23885_dev *dev);
@@ -479,11 +483,3 @@ static inline unsigned int norm_swidth(v4l2_std_id norm)
{
return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
}
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index e7136975430..078be631955 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1285,7 +1285,7 @@ static int blackbird_register_video(struct cx8802_dev *dev)
return err;
}
printk(KERN_INFO "%s/2: registered device video%d [mpeg]\n",
- dev->core->name,dev->mpeg_dev->minor & 0x1f);
+ dev->core->name, dev->mpeg_dev->num);
return 0;
}
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 5da04e811ca..5bcbb4cc7c2 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1270,27 +1270,40 @@ static const struct cx88_board cx88_boards[] = {
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_HVR3000] = {
- /* FIXME: Add dvb & radio support */
.name = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T",
.tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .audio_chip = V4L2_IDENT_WM8775,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x84bf,
+ /* 1: TV Audio / FM Mono */
+ .audioroute = 1,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x84bf,
+ /* 2: Line-In */
+ .audioroute = 2,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x84bf,
+ /* 2: Line-In */
+ .audioroute = 2,
}},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x84bf,
+ /* 4: FM Stereo (untested) */
+ .audioroute = 8,
+ },
.mpeg = CX88_MPEG_DVB,
+ .num_frontends = 2,
},
[CX88_BOARD_NORWOOD_MICRO] = {
.name = "Norwood Micro TV Tuner",
@@ -1356,23 +1369,27 @@ static const struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xef88,
+ /* 1: TV Audio / FM Mono */
.audioroute = 1,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xef88,
+ /* 2: Line-In */
.audioroute = 2,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xef88,
+ /* 2: Line-In */
.audioroute = 2,
}},
- /* fixme: Add radio support */
.mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xef88,
+ /* 4: FM Stereo (untested) */
+ .audioroute = 8,
},
},
[CX88_BOARD_ADSTECH_PTV_390] = {
@@ -1716,6 +1733,7 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .audio_chip = V4L2_IDENT_WM8775,
/*
* GPIO0 (WINTV2000)
*
@@ -1729,7 +1747,7 @@ static const struct cx88_board cx88_boards[] = {
* BIT VALUE FUNCTION GP{x}_IO
* 0 1 I:?
* 1 1 I:?
- * 2 1 O:DVB-T DEMOD ENABLE LOW/ANALOG DEMOD ENABLE HIGH
+ * 2 1 O:MPEG PORT 0=DVB-T 1=DVB-S
* 3 1 I:?
* 4 1 I:?
* 5 1 I:?
@@ -1745,22 +1763,41 @@ static const struct cx88_board cx88_boards[] = {
* d 0 I
* e 1 O
* f 1 O
+ *
+ * WM8775 ADC
+ *
+ * 1: TV Audio / FM Mono
+ * 2: Line-In
+ * 3: Line-In Expansion
+ * 4: FM Stereo
*/
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xc4bf,
+ /* 1: TV Audio / FM Mono */
+ .audioroute = 1,
}, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xc4bf,
+ /* 2: Line-In */
+ .audioroute = 2,
}, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xc4bf,
+ /* 2: Line-In */
+ .audioroute = 2,
} },
- /* fixme: Add radio support */
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0xc4bf,
+ /* 4: FM Stereo */
+ .audioroute = 8,
+ },
.mpeg = CX88_MPEG_DVB,
+ .num_frontends = 2,
},
[CX88_BOARD_HAUPPAUGE_HVR4000LITE] = {
.name = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2",
@@ -2662,10 +2699,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR4000:
- case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
/* Init GPIO */
cx_write(MO_GP0_IO, core->board.input[0].gpio0);
udelay(1000);
+ cx_clear(MO_GP0_IO, 0x00000080);
+ udelay(50);
+ cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
+ udelay(1000);
break;
}
}
@@ -3004,10 +3044,14 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
- info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ if (!core->board.num_frontends && (core->board.mpeg & CX88_MPEG_DVB))
+ core->board.num_frontends = 1;
+
+ info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n",
pci->subsystem_vendor, pci->subsystem_device, core->board.name,
core->boardnr, card[core->nr] == core->boardnr ?
- "insmod option" : "autodetected");
+ "insmod option" : "autodetected",
+ core->board.num_frontends);
if (tuner[core->nr] != UNSET)
core->board.tuner_type = tuner[core->nr];
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index d656fec5901..60705b08bfe 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -549,7 +549,8 @@ void cx88_wakeup(struct cx88_core *core,
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
}
if (bc != 1)
- printk("%s: %d buffers handled (should be 1)\n",__func__,bc);
+ dprintk(2, "%s: %d buffers handled (should be 1)\n",
+ __func__, bc);
}
void cx88_shutdown(struct cx88_core *core)
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 344ed2626e5..cf6c30d4e54 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -116,13 +116,23 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
struct cx8802_dev *dev= fe->dvb->priv;
struct cx8802_driver *drv = NULL;
int ret = 0;
+ int fe_id;
+
+ fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe);
+ if (!fe_id) {
+ printk(KERN_ERR "%s() No frontend found\n", __func__);
+ return -EINVAL;
+ }
drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
if (drv) {
- if (acquire)
+ if (acquire){
+ dev->frontends.active_fe_id = fe_id;
ret = drv->request_acquire(drv);
- else
+ } else {
ret = drv->request_release(drv);
+ dev->frontends.active_fe_id = 0;
+ }
}
return ret;
@@ -396,7 +406,7 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
cx_write(MO_GP0_IO, 0x00006060);
break;
case SEC_VOLTAGE_OFF:
- printk("LNB Voltage SEC_VOLTAGE_off\n");
+ printk("LNB Voltage SEC_VOLTAGE_off\n");
break;
}
@@ -483,6 +493,7 @@ static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
{
struct dvb_frontend *fe;
+ struct videobuf_dvb_frontend *fe0 = NULL;
struct xc2028_ctrl ctl;
struct xc2028_config cfg = {
.i2c_adap = &dev->core->i2c_adap,
@@ -490,7 +501,12 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
.ctrl = &ctl,
};
- if (!dev->dvb.frontend) {
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
+ if (!fe0->dvb.frontend) {
printk(KERN_ERR "%s/2: dvb frontend not attached. "
"Can't attach xc3028\n",
dev->core->name);
@@ -504,10 +520,13 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
*/
cx88_setup_xc3028(dev->core, &ctl);
- fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
if (!fe) {
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
dev->core->name);
+ dvb_frontend_detach(fe0->dvb.frontend);
+ dvb_unregister_frontend(fe0->dvb.frontend);
+ fe0->dvb.frontend = NULL;
return -EINVAL;
}
@@ -532,8 +551,10 @@ static int cx24116_reset_device(struct dvb_frontend *fe)
struct cx88_core *core = dev->core;
/* Reset the part */
+ /* Put the cx24116 into reset */
cx_write(MO_SRST_IO, 0);
msleep(10);
+ /* Take the cx24116 out of reset */
cx_write(MO_SRST_IO, 1);
msleep(10);
@@ -554,14 +575,14 @@ static struct cx24116_config tevii_s460_config = {
static struct stv0299_config tevii_tuner_sharp_config = {
.demod_address = 0x68,
- .inittab = sharp_z0194a__inittab,
+ .inittab = sharp_z0194a_inittab,
.mclk = 88000000UL,
.invert = 1,
.skip_reinit = 0,
.lock_output = 1,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
- .set_symbol_rate = sharp_z0194a__set_symbol_rate,
+ .set_symbol_rate = sharp_z0194a_set_symbol_rate,
.set_ts_params = cx24116_set_ts_param,
};
@@ -574,19 +595,25 @@ static struct stv0288_config tevii_tuner_earda_config = {
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 */
- /* init struct videobuf_dvb */
- dev->dvb.name = core->name;
- dev->ts_gen_cntrl = 0x0c;
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
+ /* multi-frontend gate control is undefined or defaults to fe0 */
+ dev->frontends.gate = 0;
- /* init frontend */
+ /* init frontend(s) */
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_DVB_T1:
- dev->dvb.frontend = dvb_attach(cx22702_attach,
+ fe0->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, &core->i2c_adap,
DVB_PLL_THOMSON_DTT759X))
goto frontend_detach;
@@ -596,11 +623,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_CONEXANT_DVB_T1:
case CX88_BOARD_KWORLD_DVB_T_CX22702:
case CX88_BOARD_WINFAST_DTV1000:
- dev->dvb.frontend = dvb_attach(cx22702_attach,
+ fe0->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x60, &core->i2c_adap,
DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
@@ -610,33 +637,67 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
case CX88_BOARD_HAUPPAUGE_HVR1300:
- case CX88_BOARD_HAUPPAUGE_HVR3000:
- dev->dvb.frontend = dvb_attach(cx22702_attach,
+ fe0->dvb.frontend = dvb_attach(cx22702_attach,
&hauppauge_hvr_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_PHILIPS_FMD1216ME_MK3))
goto frontend_detach;
}
break;
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ /* DVB-S init */
+ fe0->dvb.frontend = dvb_attach(cx24123_attach,
+ &hauppauge_novas_config,
+ &dev->core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
+ &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) {
+ dprintk( 1, "%s(): HVR3000 - DVB-S LNB Init: failed\n", __func__);
+ }
+ } else {
+ dprintk( 1, "%s(): HVR3000 - DVB-S Init: failed\n", __func__);
+ }
+ /* DVB-T init */
+ fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+ if (fe1) {
+ dev->frontends.gate = 2;
+ mfe_shared = 1;
+ fe1->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_hvr_config,
+ &dev->core->i2c_adap);
+ if (fe1->dvb.frontend) {
+ fe1->dvb.frontend->id = 1;
+ if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3)) {
+ dprintk( 1, "%s(): HVR3000 - DVB-T misc Init: failed\n", __func__);
+ }
+ } else {
+ dprintk( 1, "%s(): HVR3000 - DVB-T Init: failed\n", __func__);
+ }
+ } else {
+ dprintk( 1, "%s(): HVR3000 - DVB-T Init: can't find frontend 2.\n", __func__);
+ }
+ break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
- dev->dvb.frontend = dvb_attach(mt352_attach,
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x60, NULL, DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
break;
}
/* ZL10353 replaces MT352 on later cards */
- dev->dvb.frontend = dvb_attach(zl10353_attach,
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_plus_v1_1,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x60, NULL, DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
}
@@ -644,31 +705,31 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
/* The tin box says DEE1601, but it seems to be DTT7579
* compatible, with a slightly different MT352 AGC gain. */
- dev->dvb.frontend = dvb_attach(mt352_attach,
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv_dual,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, NULL, DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
break;
}
/* ZL10353 replaces MT352 on later cards */
- dev->dvb.frontend = dvb_attach(zl10353_attach,
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_plus_v1_1,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, NULL, DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
- dev->dvb.frontend = dvb_attach(mt352_attach,
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, NULL, DVB_PLL_LG_Z201))
goto frontend_detach;
}
@@ -676,11 +737,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_DNTV_LIVE_DVB_T:
case CX88_BOARD_ADSTECH_DVB_T_PCI:
- dev->dvb.frontend = dvb_attach(mt352_attach,
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
&dntv_live_dvbt_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, NULL, DVB_PLL_UNKNOWN_1))
goto frontend_detach;
}
@@ -688,10 +749,10 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
/* MT352 is on a secondary I2C bus made from some GPIO lines */
- dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
+ fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&dev->vp3054->adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_PHILIPS_FMD1216ME_MK3))
goto frontend_detach;
@@ -702,22 +763,22 @@ static int dvb_register(struct cx8802_dev *dev)
#endif
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
- dev->dvb.frontend = dvb_attach(zl10353_attach,
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_hybrid,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_THOMSON_FE6600))
goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
- dev->dvb.frontend = dvb_attach(zl10353_attach,
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_xc3028,
&core->i2c_adap);
- if (dev->dvb.frontend == NULL)
- dev->dvb.frontend = dvb_attach(mt352_attach,
+ if (fe0->dvb.frontend == NULL)
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv_mt352_xc3028,
&core->i2c_adap);
/*
@@ -725,16 +786,16 @@ static int dvb_register(struct cx8802_dev *dev)
* We must not permit gate_ctrl to be performed, or
* the xc3028 cannot communicate on the bus.
*/
- if (dev->dvb.frontend)
- dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (fe0->dvb.frontend)
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
if (attach_xc3028(0x61, dev) < 0)
- return -EINVAL;
+ goto frontend_detach;
break;
case CX88_BOARD_PCHDTV_HD3000:
- dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
+ fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_THOMSON_DTT761X))
goto frontend_detach;
@@ -751,11 +812,11 @@ static int dvb_register(struct cx8802_dev *dev)
/* Select RF connector callback */
fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
- dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_3_gold,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_MICROTUNE_4042FI5))
goto frontend_detach;
@@ -769,11 +830,11 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 9);
mdelay(200);
- dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_3_gold,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_THOMSON_DTT761X))
goto frontend_detach;
@@ -787,15 +848,15 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
- dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_5_gold,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_LG_TDVS_H06XF))
goto frontend_detach;
- if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+ if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x43))
goto frontend_detach;
}
@@ -808,25 +869,25 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
- dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&pchdtv_hd5500,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_LG_TDVS_H06XF))
goto frontend_detach;
- if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+ if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x43))
goto frontend_detach;
}
break;
case CX88_BOARD_ATI_HDTVWONDER:
- dev->dvb.frontend = dvb_attach(nxt200x_attach,
+ fe0->dvb.frontend = dvb_attach(nxt200x_attach,
&ati_hdtvwonder,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_PHILIPS_TUV1236D))
goto frontend_detach;
@@ -834,49 +895,49 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
- dev->dvb.frontend = dvb_attach(cx24123_attach,
+ fe0->dvb.frontend = dvb_attach(cx24123_attach,
&hauppauge_novas_config,
&core->i2c_adap);
- if (dev->dvb.frontend) {
- if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend) {
+ if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
goto frontend_detach;
}
break;
case CX88_BOARD_KWORLD_DVBS_100:
- dev->dvb.frontend = dvb_attach(cx24123_attach,
+ fe0->dvb.frontend = dvb_attach(cx24123_attach,
&kworld_dvbs_100_config,
&core->i2c_adap);
- if (dev->dvb.frontend) {
- core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
- dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+ if (fe0->dvb.frontend) {
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
}
break;
case CX88_BOARD_GENIATECH_DVBS:
- dev->dvb.frontend = dvb_attach(cx24123_attach,
+ fe0->dvb.frontend = dvb_attach(cx24123_attach,
&geniatech_dvbs_config,
&core->i2c_adap);
- if (dev->dvb.frontend) {
- core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
- dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
+ if (fe0->dvb.frontend) {
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
}
break;
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
- dev->dvb.frontend = dvb_attach(s5h1409_attach,
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&pinnacle_pctv_hd_800i_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
&core->i2c_adap,
&pinnacle_pctv_hd_800i_tuner_config))
goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
- dev->dvb.frontend = dvb_attach(s5h1409_attach,
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&dvico_hdtv5_pci_nano_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
+ if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &core->i2c_adap,
@@ -889,17 +950,17 @@ static int dvb_register(struct cx8802_dev *dev)
};
fe = dvb_attach(xc2028_attach,
- dev->dvb.frontend, &cfg);
+ fe0->dvb.frontend, &cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
}
break;
case CX88_BOARD_PINNACLE_HYBRID_PCTV:
- dev->dvb.frontend = dvb_attach(zl10353_attach,
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
&cx88_pinnacle_hybrid_pctv,
&core->i2c_adap);
- if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
if (attach_xc3028(0x61, dev) < 0)
goto frontend_detach;
}
@@ -907,85 +968,117 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_GENIATECH_X8000_MT:
dev->ts_gen_cntrl = 0x00;
- dev->dvb.frontend = dvb_attach(zl10353_attach,
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
&cx88_geniatech_x8000_mt,
&core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
goto frontend_detach;
break;
case CX88_BOARD_KWORLD_ATSC_120:
- dev->dvb.frontend = dvb_attach(s5h1409_attach,
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&kworld_atsc_120_config,
&core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
goto frontend_detach;
break;
case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
- dev->dvb.frontend = dvb_attach(s5h1411_attach,
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
&dvico_fusionhdtv7_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
&core->i2c_adap,
&dvico_fusionhdtv7_tuner_config))
goto frontend_detach;
}
break;
case CX88_BOARD_HAUPPAUGE_HVR4000:
+ /* DVB-S/S2 Init */
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
+ &hauppauge_hvr4000_config,
+ &dev->core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if(!dvb_attach(isl6421_attach, fe0->dvb.frontend,
+ &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) {
+ dprintk( 1, "%s(): HVR4000 - DVB-S LNB Init: failed\n", __func__);
+ }
+ } else {
+ dprintk( 1, "%s(): HVR4000 - DVB-S Init: failed\n", __func__);
+ }
+ /* DVB-T Init */
+ fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+ if (fe1) {
+ dev->frontends.gate = 2;
+ mfe_shared = 1;
+ fe1->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_hvr_config,
+ &dev->core->i2c_adap);
+ if (fe1->dvb.frontend) {
+ fe1->dvb.frontend->id = 1;
+ if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3)) {
+ dprintk( 1, "%s(): HVR4000 - DVB-T misc Init: failed\n", __func__);
+ }
+ } else {
+ dprintk( 1, "%s(): HVR4000 - DVB-T Init: failed\n", __func__);
+ }
+ } else {
+ dprintk( 1, "%s(): HVR4000 - DVB-T Init: can't find frontend 2.\n", __func__);
+ }
+ break;
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
- /* Support for DVB-S only, not DVB-T support */
- dev->dvb.frontend = dvb_attach(cx24116_attach,
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
&hauppauge_hvr4000_config,
&dev->core->i2c_adap);
- if (dev->dvb.frontend) {
- dvb_attach(isl6421_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend) {
+ dvb_attach(isl6421_attach, fe0->dvb.frontend,
&dev->core->i2c_adap,
0x08, ISL6421_DCL, 0x00);
}
break;
case CX88_BOARD_TEVII_S420:
- dev->dvb.frontend = dvb_attach(stv0299_attach,
+ fe0->dvb.frontend = dvb_attach(stv0299_attach,
&tevii_tuner_sharp_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
&core->i2c_adap, DVB_PLL_OPERA1))
goto frontend_detach;
- core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
- dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
} else {
- dev->dvb.frontend = dvb_attach(stv0288_attach,
+ fe0->dvb.frontend = dvb_attach(stv0288_attach,
&tevii_tuner_earda_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- if (!dvb_attach(stb6000_attach, dev->dvb.frontend, 0x61,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
&core->i2c_adap))
goto frontend_detach;
- core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
- dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
-
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
}
}
break;
case CX88_BOARD_TEVII_S460:
- dev->dvb.frontend = dvb_attach(cx24116_attach,
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
&tevii_s460_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
- dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+ if (fe0->dvb.frontend != NULL) {
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
}
break;
case CX88_BOARD_OMICOM_SS4_PCI:
case CX88_BOARD_TBS_8920:
case CX88_BOARD_PROF_7300:
- dev->dvb.frontend = dvb_attach(cx24116_attach,
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
&hauppauge_hvr4000_config,
&core->i2c_adap);
- if (dev->dvb.frontend != NULL) {
- core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
- dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+ if (fe0->dvb.frontend != NULL) {
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
}
break;
default:
@@ -993,30 +1086,30 @@ static int dvb_register(struct cx8802_dev *dev)
core->name);
break;
}
- if (NULL == dev->dvb.frontend) {
+
+ if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
printk(KERN_ERR
"%s/2: frontend initialization failed\n",
core->name);
return -EINVAL;
}
/* define general-purpose callback pointer */
- dev->dvb.frontend->callback = cx88_tuner_callback;
+ fe0->dvb.frontend->callback = cx88_tuner_callback;
/* Ensure all frontends negotiate bus access */
- dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
+ fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
+ if (fe1)
+ fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
/* Put the analog decoder in standby to keep it quiet */
cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
/* register everything */
- return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
- &dev->pci->dev, adapter_nr);
+ return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ &dev->pci->dev, adapter_nr, mfe_shared);
frontend_detach:
- if (dev->dvb.frontend) {
- dvb_frontend_detach(dev->dvb.frontend);
- dev->dvb.frontend = NULL;
- }
+ videobuf_dvb_dealloc_frontends(&dev->frontends);
return -EINVAL;
}
@@ -1039,6 +1132,38 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
cx_clear(MO_GP0_IO, 0x00000004);
udelay(1000);
break;
+
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ case CX88_BOARD_HAUPPAUGE_HVR4000:
+ if(core->dvbdev->frontends.active_fe_id == 1) {
+ /* DVB-S/S2 Enabled */
+
+ /* Toggle reset on cx22702 leaving i2c active */
+ cx_write(MO_GP0_IO, (core->board.input[0].gpio0 & 0x0000ff00) | 0x00000080);
+ udelay(1000);
+ cx_clear(MO_GP0_IO, 0x00000080);
+ udelay(50);
+ cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset */
+ cx_set(MO_GP0_IO, 0x00000004); /* tri-state the cx22702 pins */
+ udelay(1000);
+
+ cx_write(MO_SRST_IO, 1); /* Take the cx24116/cx24123 out of reset */
+ core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
+ } else
+ if (core->dvbdev->frontends.active_fe_id == 2) {
+ /* DVB-T Enabled */
+
+ /* Put the cx24116/cx24123 into reset */
+ cx_write(MO_SRST_IO, 0);
+
+ /* cx22702 out of reset and enable it */
+ cx_set(MO_GP0_IO, 0x00000080);
+ cx_clear(MO_GP0_IO, 0x00000004);
+ core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
+ udelay(1000);
+ }
+ break;
+
default:
err = -ENODEV;
}
@@ -1056,6 +1181,9 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* Do Nothing, leave the cx22702 on the bus. */
break;
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ case CX88_BOARD_HAUPPAUGE_HVR4000:
+ break;
default:
err = -ENODEV;
}
@@ -1066,7 +1194,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
struct cx8802_dev *dev = drv->core->dvbdev;
- int err;
+ int err, i;
+ struct videobuf_dvb_frontend *fe;
dprintk( 1, "%s\n", __func__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
@@ -1086,28 +1215,39 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
/* dvb stuff */
printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
- videobuf_queue_sg_init(&dev->dvb.dvbq, &dvb_qops,
+ dev->ts_gen_cntrl = 0x0c;
+
+ for (i = 1; i <= core->board.num_frontends; i++) {
+ fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i);
+ if (!fe) {
+ printk(KERN_ERR "%s() failed to get frontend(%d)\n", __func__, i);
+ continue;
+ }
+ videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_TOP,
sizeof(struct cx88_buffer),
dev);
+ /* init struct videobuf_dvb */
+ fe->dvb.name = dev->core->name;
+ }
err = dvb_register(dev);
if (err != 0)
printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
core->name, err);
-
- fail_core:
+fail_core:
return err;
}
static int cx8802_dvb_remove(struct cx8802_driver *drv)
{
+ struct cx88_core *core = drv->core;
struct cx8802_dev *dev = drv->core->dvbdev;
- /* dvb */
- if (dev->dvb.frontend)
- videobuf_dvb_unregister(&dev->dvb);
+ dprintk( 1, "%s\n", __func__);
+
+ videobuf_dvb_unregister_bus(&dev->frontends);
vp3054_i2c_remove(dev);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 8e74d64fdcd..1ab691d2069 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -116,18 +116,27 @@ 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) && (core->dvbdev->dvb.frontend) ) {
- if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
- core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+ 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 (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);
- if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
- core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+ 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);
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index a6b061c2644..a1c435b4b1c 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -769,6 +769,10 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
struct cx8802_dev *dev;
struct cx88_core *core;
int err;
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+ struct videobuf_dvb_frontend *demod;
+ int i;
+#endif
/* general setup */
core = cx88_core_get(pci_dev);
@@ -795,6 +799,23 @@ 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)
+ printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, core->board.num_frontends);
+
+ for (i = 1; i <= core->board.num_frontends; i++) {
+ demod = videobuf_dvb_alloc_frontend(&dev->frontends, i);
+ if(demod == NULL) {
+ printk(KERN_ERR "%s() failed to alloc\n", __func__);
+ err = -ENOMEM;
+ goto fail_free;
+ }
+ }
+#endif
+
/* Maintain a reference so cx88-video can query the 8802 device. */
core->dvbdev = dev;
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 3a1977f41e2..7dd506b987f 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -767,6 +767,14 @@ void cx88_set_tvaudio(struct cx88_core *core)
case WW_FM:
set_audio_standard_FM(core, radio_deemphasis);
break;
+ case WW_I2SADC:
+ set_audio_start(core, 0x01);
+ /* Slave/Philips/Autobaud */
+ cx_write(AUD_I2SINPUTCNTL, 0);
+ /* Switch to "I2S ADC mode" */
+ cx_write(AUD_I2SCNTL, 0x1);
+ set_audio_finish(core, EN_I2SIN_ENABLE);
+ break;
case WW_NONE:
default:
printk("%s/0: unknown tv audio mode [%d]\n",
@@ -895,6 +903,9 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
break;
}
break;
+ case WW_I2SADC:
+ /* DO NOTHING */
+ break;
}
if (UNSET != ctl) {
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index be45955dff6..61265fd04d5 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -426,24 +426,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
/* if there are audioroutes defined, we have an external
ADC to deal with audio */
-
if (INPUT(input).audioroute) {
-
- /* cx2388's C-ADC is connected to the tuner only.
- When used with S-Video, that ADC is busy dealing with
- chroma, so an external must be used for baseband audio */
-
- if (INPUT(input).type != CX88_VMUX_TELEVISION &&
- INPUT(input).type != CX88_RADIO) {
- /* "ADC mode" */
- cx_write(AUD_I2SCNTL, 0x1);
- cx_set(AUD_CTL, EN_I2SIN_ENABLE);
- } else {
- /* Normal mode */
- cx_write(AUD_I2SCNTL, 0x0);
- cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
- }
-
/* The wm8775 module has the "2" route hardwired into
the initialization. Some boards may use different
routes for different inputs. HVR-1300 surely does */
@@ -454,9 +437,19 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
route.input = INPUT(input).audioroute;
cx88_call_i2c_clients(core,
VIDIOC_INT_S_AUDIO_ROUTING, &route);
-
}
-
+ /* cx2388's C-ADC is connected to the tuner only.
+ When used with S-Video, that ADC is busy dealing with
+ chroma, so an external must be used for baseband audio */
+ if (INPUT(input).type != CX88_VMUX_TELEVISION ) {
+ /* "I2S ADC mode" */
+ core->tvaudio = WW_I2SADC;
+ cx88_set_tvaudio(core);
+ } else {
+ /* Normal mode */
+ cx_write(AUD_I2SCNTL, 0x0);
+ cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+ }
}
return 0;
@@ -832,9 +825,24 @@ static int video_open(struct inode *inode, struct file *file)
cx_write(MO_GP0_IO, core->board.radio.gpio0);
cx_write(MO_GP1_IO, core->board.radio.gpio1);
cx_write(MO_GP2_IO, core->board.radio.gpio2);
- core->tvaudio = WW_FM;
- cx88_set_tvaudio(core);
- cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
+ if (core->board.radio.audioroute) {
+ if(core->board.audio_chip &&
+ core->board.audio_chip == V4L2_IDENT_WM8775) {
+ struct v4l2_routing route;
+
+ route.input = core->board.radio.audioroute;
+ cx88_call_i2c_clients(core,
+ VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ }
+ /* "I2S ADC mode" */
+ core->tvaudio = WW_I2SADC;
+ cx88_set_tvaudio(core);
+ } else {
+ /* FM Mode */
+ core->tvaudio = WW_FM;
+ cx88_set_tvaudio(core);
+ cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
+ }
cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
}
unlock_kernel();
@@ -1903,7 +1911,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
goto fail_unreg;
}
printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n",
- core->name,dev->video_dev->minor & 0x1f);
+ core->name, dev->video_dev->num);
dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi");
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
@@ -1914,7 +1922,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
goto fail_unreg;
}
printk(KERN_INFO "%s/0: registered device vbi%d\n",
- core->name,dev->vbi_dev->minor & 0x1f);
+ core->name, dev->vbi_dev->num);
if (core->board.radio.type == CX88_RADIO) {
dev->radio_dev = cx88_vdev_init(core,dev->pci,
@@ -1927,7 +1935,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
goto fail_unreg;
}
printk(KERN_INFO "%s/0: registered device radio%d\n",
- core->name,dev->radio_dev->minor & 0x1f);
+ core->name, dev->radio_dev->num);
}
/* everything worked */
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index dbf01b8b57a..76207c2856b 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -247,7 +247,7 @@ struct cx88_input {
enum cx88_itype type;
u32 gpio0, gpio1, gpio2, gpio3;
unsigned int vmux:2;
- unsigned int audioroute:2;
+ unsigned int audioroute:4;
};
struct cx88_board {
@@ -261,6 +261,7 @@ struct cx88_board {
struct cx88_input radio;
enum cx88_board_type mpeg;
unsigned int audio_chip;
+ int num_frontends;
};
struct cx88_subid {
@@ -356,6 +357,7 @@ struct cx88_core {
struct cx8802_dev *dvbdev;
enum cx88_board_type active_type_id;
int active_ref;
+ int active_fe_id;
};
struct cx8800_dev;
@@ -490,7 +492,7 @@ struct cx8802_dev {
#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
/* for dvb only */
- struct videobuf_dvb dvb;
+ struct videobuf_dvb_frontends frontends;
#endif
#if defined(CONFIG_VIDEO_CX88_VP3054) || \
@@ -628,6 +630,7 @@ extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
#define WW_EIAJ 7
#define WW_I2SPT 8
#define WW_FM 9
+#define WW_I2SADC 10
void cx88_set_tvaudio(struct cx88_core *core);
void cx88_newstation(struct cx88_core *core);
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index 3aa538afcc0..298810d5262 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -192,7 +192,7 @@ static void dabusb_iso_complete (struct urb *purb)
err("dabusb_iso_complete: invalid len %d", len);
}
else
- warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status);
+ dev_warn(&purb->dev->dev, "dabusb_iso_complete: corrupted packet status: %d\n", purb->iso_frame_desc[i].status);
if (dst != purb->actual_length)
err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length);
}
@@ -289,7 +289,7 @@ static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
}
if( ret == -EPIPE ) {
- warn("CLEAR_FEATURE request to remove STALL condition.");
+ dev_warn(&s->usbdev->dev, "CLEAR_FEATURE request to remove STALL condition.\n");
if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
err("request failed");
}
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index c53649e5315..a1ab2ef4557 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -2042,7 +2042,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
goto fail_unreg;
}
em28xx_info("Registered radio device as /dev/radio%d\n",
- dev->radio_dev->minor & 0x1f);
+ dev->radio_dev->num);
}
/* init video dma queues */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 7a85c41b0ee..9d0ef96c23f 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -588,7 +588,7 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "URB timeout reached. The camera is misconfigured. To "
"use it, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -EIO;
}
@@ -1195,7 +1195,7 @@ static void et61x251_release_resources(struct kref *kref)
cam = container_of(kref, struct et61x251_device, kref);
- DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+ DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
usb_put_dev(cam->usbdev);
@@ -1237,7 +1237,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
if (cam->users) {
DBG(2, "Device /dev/video%d is already in use",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
@@ -1280,7 +1280,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
cam->frame_count = 0;
et61x251_empty_framequeues(cam);
- DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+ DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num);
out:
mutex_unlock(&cam->open_mutex);
@@ -1304,7 +1304,7 @@ static int et61x251_release(struct inode* inode, struct file* filp)
cam->users--;
wake_up_interruptible_nr(&cam->wait_open, 1);
- DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+ DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num);
kref_put(&cam->kref, et61x251_release_resources);
@@ -1845,7 +1845,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -EIO;
}
@@ -1858,7 +1858,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -ENOMEM;
}
@@ -2068,7 +2068,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -EIO;
}
@@ -2080,7 +2080,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -ENOMEM;
}
@@ -2128,7 +2128,7 @@ et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
"problems. To use the camera, close and open "
- "/dev/video%d again.", cam->v4ldev->minor);
+ "/dev/video%d again.", cam->v4ldev->num);
return -EIO;
}
@@ -2605,7 +2605,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+ DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num);
cam->module_param.force_munmap = force_munmap[dev_nr];
cam->module_param.frame_timeout = frame_timeout[dev_nr];
@@ -2658,7 +2658,7 @@ static void et61x251_usb_disconnect(struct usb_interface* intf)
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
"memory deallocation are deferred.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
cam->state |= DEV_MISCONFIGURED;
et61x251_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index c21af312ee7..e48fbfc8ad0 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -21,6 +21,7 @@
#define MODULE_NAME "gspca"
#include <linux/init.h>
+#include <linux/version.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
@@ -403,7 +404,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
unsigned int i;
PDEBUG(D_STREAM, "kill transfer");
- for (i = 0; i < MAX_NURBS; ++i) {
+ for (i = 0; i < MAX_NURBS; i++) {
urb = gspca_dev->urb[i];
if (urb == NULL)
break;
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 4779dd0b06d..1d9dc90b479 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -2,7 +2,6 @@
#define GSPCAV2_H
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h
index c786d7d3d44..1a37ae4bc82 100644
--- a/drivers/media/video/gspca/m5602/m5602_bridge.h
+++ b/drivers/media/video/gspca/m5602/m5602_bridge.h
@@ -1,7 +1,7 @@
/*
* USB Driver for ALi m5602 based webcams
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -25,33 +25,6 @@
/*****************************************************************************/
-#undef PDEBUG
-#undef info
-#undef err
-
-#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
- format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \
- format "\n" , ## arg)
-
-/* Debug parameters */
-#define DBG_INIT 0x1
-#define DBG_PROBE 0x2
-#define DBG_V4L2 0x4
-#define DBG_TRACE 0x8
-#define DBG_DATA 0x10
-#define DBG_V4L2_CID 0x20
-#define DBG_GSPCA 0x40
-
-#define PDEBUG(level, fmt, args...) \
- do { \
- if (m5602_debug & level) \
- info("[%s:%d] " fmt, __func__, __LINE__ , \
- ## args); \
- } while (0)
-
-/*****************************************************************************/
-
#define M5602_XB_SENSOR_TYPE 0x00
#define M5602_XB_SENSOR_CTRL 0x01
#define M5602_XB_LINE_OF_FRAME_H 0x02
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index 19d5e351ccc..fd6ce384b48 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -1,7 +1,7 @@
-/*
+ /*
* USB Driver for ALi m5602 based webcams
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -26,7 +26,6 @@
int force_sensor;
int dump_bridge;
int dump_sensor;
-unsigned int m5602_debug;
static const __devinitdata struct usb_device_id m5602_table[] = {
{USB_DEVICE(0x0402, 0x5602)},
@@ -48,7 +47,7 @@ int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
1, M5602_URB_MSG_TIMEOUT);
*i2c_data = buf[0];
- PDEBUG(DBG_TRACE, "Reading bridge register 0x%x containing 0x%x",
+ PDEBUG(D_CONF, "Reading bridge register 0x%x containing 0x%x",
address, *i2c_data);
/* usb_control_msg(...) returns the number of bytes sent upon success,
@@ -63,7 +62,7 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
- PDEBUG(DBG_TRACE, "Writing bridge register 0x%x with 0x%x",
+ PDEBUG(D_CONF, "Writing bridge register 0x%x with 0x%x",
address, i2c_data);
memcpy(buf, bridge_urb_skeleton,
@@ -91,7 +90,8 @@ static void m5602_dump_bridge(struct sd *sd)
m5602_read_bridge(sd, i, &val);
info("ALi m5602 address 0x%x contains 0x%x", i, val);
}
- info("Warning: The camera probably won't work until it's power cycled");
+ info("Warning: The ALi m5602 webcam probably won't work "
+ "until it's power cycled");
}
static int m5602_probe_sensor(struct sd *sd)
@@ -135,7 +135,7 @@ static int m5602_init(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int err;
- PDEBUG(DBG_TRACE, "Initializing ALi m5602 webcam");
+ PDEBUG(D_CONF, "Initializing ALi m5602 webcam");
/* Run the init sequence */
err = sd->sensor->init(sd);
@@ -146,16 +146,18 @@ static int m5602_start_transfer(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 *buf = sd->gspca_dev.usb_buf;
+ int err;
/* Send start command to the camera */
const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};
memcpy(buf, buffer, sizeof(buffer));
- usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
- 0x04, 0x40, 0x19, 0x0000, buf,
- 4, M5602_URB_MSG_TIMEOUT);
+ err = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x04, 0x40, 0x19, 0x0000, buf,
+ 4, M5602_URB_MSG_TIMEOUT);
- PDEBUG(DBG_V4L2, "Transfer started");
- return 0;
+ PDEBUG(D_STREAM, "Transfer started");
+ return (err < 0) ? err : 0;
}
static void m5602_urb_complete(struct gspca_dev *gspca_dev,
@@ -165,14 +167,14 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
if (len < 6) {
- PDEBUG(DBG_DATA, "Packet is less than 6 bytes");
+ PDEBUG(D_PACK, "Packet is less than 6 bytes");
return;
}
/* Frame delimiter: ff xx xx xx ff ff */
if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff &&
data[2] != sd->frame_id) {
- PDEBUG(DBG_DATA, "Frame delimiter detected");
+ PDEBUG(D_FRAM, "Frame delimiter detected");
sd->frame_id = data[2];
/* Remove the extra fluff appended on each header */
@@ -187,7 +189,7 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
/* Create a new frame */
gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
- PDEBUG(DBG_V4L2, "Starting new frame %d",
+ PDEBUG(D_FRAM, "Starting new frame %d",
sd->frame_count);
} else {
@@ -198,7 +200,7 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
len -= 4;
if (cur_frame_len + len <= frame->v4l2_buf.length) {
- PDEBUG(DBG_DATA, "Continuing frame %d copying %d bytes",
+ PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
sd->frame_count, len);
gspca_frame_add(gspca_dev, INTER_PACKET, frame,
@@ -234,8 +236,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
struct cam *cam;
int err;
- PDEBUG(DBG_GSPCA, "m5602_configure start");
-
cam = &gspca_dev->cam;
cam->epaddr = M5602_ISOC_ENDPOINT_ADDR;
sd->desc = &sd_desc;
@@ -248,11 +248,10 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
if (err)
goto fail;
- PDEBUG(DBG_GSPCA, "m5602_configure end");
return 0;
fail:
- PDEBUG(DBG_GSPCA, "m5602_configure failed");
+ PDEBUG(D_ERR, "ALi m5602 webcam failed");
cam->cam_mode = NULL;
cam->nmodes = 0;
@@ -282,13 +281,13 @@ static int __init mod_m5602_init(void)
{
if (usb_register(&sd_driver) < 0)
return -1;
- PDEBUG(D_PROBE, "m5602 module registered");
+ PDEBUG(D_PROBE, "registered");
return 0;
}
static void __exit mod_m5602_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "m5602 module deregistered");
+ PDEBUG(D_PROBE, "deregistered");
}
module_init(mod_m5602_init);
@@ -297,9 +296,6 @@ module_exit(mod_m5602_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param_named(debug, m5602_debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "toggles debug on/off");
-
module_param(force_sensor, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(force_sensor,
"force detection of sensor, "
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
index 566d4925a0e..fb700c2d055 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.c
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
@@ -1,7 +1,7 @@
/*
* Driver for the mt9m111 sensor
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -107,7 +107,7 @@ int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
*val = data[0] & MT9M111_RMB_MIRROR_ROWS;
- PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+ PDEBUG(D_V4L2, "Read vertical flip %d", *val);
return (err < 0) ? err : 0;
}
@@ -118,7 +118,7 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+ PDEBUG(D_V4L2, "Set vertical flip to %d", val);
/* Set the correct page map */
err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@@ -145,7 +145,7 @@ int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
*val = data[0] & MT9M111_RMB_MIRROR_COLS;
- PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+ PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
return (err < 0) ? err : 0;
}
@@ -156,7 +156,7 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
+ PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
/* Set the correct page map */
err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@@ -188,7 +188,7 @@ int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
((tmp & (1 << 8)) * 2) |
(tmp & 0x7f);
- PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+ PDEBUG(D_V4L2, "Read gain %d", *val);
return (err < 0) ? err : 0;
}
@@ -222,7 +222,7 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
data[1] = (tmp & 0xff00) >> 8;
data[0] = (tmp & 0xff);
- PDEBUG(DBG_V4L2_CID, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
+ PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
data[1], data[0]);
err = mt9m111_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
@@ -257,7 +257,7 @@ int mt9m111_read_sensor(struct sd *sd, const u8 address,
for (i = 0; i < len && !err; i++) {
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
- PDEBUG(DBG_TRACE, "Reading sensor register "
+ PDEBUG(D_CONF, "Reading sensor register "
"0x%x contains 0x%x ", address, *i2c_data);
}
out:
@@ -290,7 +290,7 @@ int mt9m111_write_sensor(struct sd *sd, const u8 address,
memcpy(p, sensor_urb_skeleton + 16, 4);
p[3] = i2c_data[i];
p += 4;
- PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+ PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
address, i2c_data[i]);
}
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
index 79a5d887819..315209d5aee 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.h
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
@@ -1,7 +1,7 @@
/*
* Driver for the mt9m111 sensor
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -82,7 +82,6 @@
/* Kernel module parameters */
extern int force_sensor;
extern int dump_sensor;
-extern unsigned int m5602_debug;
int mt9m111_probe(struct sd *sd);
int mt9m111_init(struct sd *sd);
@@ -152,8 +151,8 @@ static struct m5602_sensor mt9m111 = {
.default_value = DEFAULT_GAIN,
.flags = V4L2_CTRL_FLAG_SLIDER
},
- .set = mt9m111_set_hflip,
- .get = mt9m111_get_hflip
+ .set = mt9m111_set_gain,
+ .get = mt9m111_get_gain
}
},
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c
index 31c5896250e..837c7e47661 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.c
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -1,7 +1,7 @@
/*
* Driver for the ov9650 sensor
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -40,7 +40,7 @@ int ov9650_read_sensor(struct sd *sd, const u8 address,
for (i = 0; i < len; i++) {
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
- PDEBUG(DBG_TRACE, "Reading sensor register "
+ PDEBUG(D_CONF, "Reading sensor register "
"0x%x containing 0x%x ", address, *i2c_data);
}
return (err < 0) ? err : 0;
@@ -72,7 +72,7 @@ int ov9650_write_sensor(struct sd *sd, const u8 address,
memcpy(p, sensor_urb_skeleton + 16, 4);
p[3] = i2c_data[i];
p += 4;
- PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+ PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
address, i2c_data[i]);
}
@@ -199,7 +199,7 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
goto out;
*val |= (i2c_data & 0x3f) << 10;
- PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
+ PDEBUG(D_V4L2, "Read exposure %d", *val);
out:
return (err < 0) ? err : 0;
}
@@ -210,7 +210,7 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
int err;
- PDEBUG(DBG_V4L2_CID, "Set exposure to %d",
+ PDEBUG(D_V4L2, "Set exposure to %d",
val & 0xffff);
/* The 6 MSBs */
@@ -246,7 +246,7 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
*val |= i2c_data;
- PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+ PDEBUG(D_V4L2, "Read gain %d", *val);
return (err < 0) ? err : 0;
}
@@ -280,7 +280,7 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
err = ov9650_read_sensor(sd, OV9650_RED, &i2c_data, 1);
*val = i2c_data;
- PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
+ PDEBUG(D_V4L2, "Read red gain %d", *val);
return (err < 0) ? err : 0;
}
@@ -291,7 +291,7 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(DBG_V4L2_CID, "Set red gain to %d",
+ PDEBUG(D_V4L2, "Set red gain to %d",
val & 0xff);
i2c_data = val & 0xff;
@@ -309,7 +309,7 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
err = ov9650_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
*val = i2c_data;
- PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
+ PDEBUG(D_V4L2, "Read blue gain %d", *val);
return (err < 0) ? err : 0;
}
@@ -320,7 +320,7 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(DBG_V4L2_CID, "Set blue gain to %d",
+ PDEBUG(D_V4L2, "Set blue gain to %d",
val & 0xff);
i2c_data = val & 0xff;
@@ -340,7 +340,7 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
*val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1;
else
*val = (i2c_data & OV9650_HFLIP) >> 5;
- PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+ PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
return (err < 0) ? err : 0;
}
@@ -351,7 +351,7 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
+ PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (err < 0)
goto out;
@@ -379,7 +379,7 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
*val = ((i2c_data & 0x10) >> 4) ? 0 : 1;
else
*val = (i2c_data & 0x10) >> 4;
- PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+ PDEBUG(D_V4L2, "Read vertical flip %d", *val);
return (err < 0) ? err : 0;
}
@@ -390,7 +390,7 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+ PDEBUG(D_V4L2, "Set vertical flip to %d", val);
err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (err < 0)
goto out;
@@ -420,7 +420,7 @@ int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
*val |= i2c_data;
- PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+ PDEBUG(D_V4L2, "Read gain %d", *val);
out:
return (err < 0) ? err : 0;
}
@@ -431,7 +431,7 @@ int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(DBG_V4L2_CID, "Set gain to %d", val & 0x3ff);
+ PDEBUG(D_V4L2, "Set gain to %d", val & 0x3ff);
/* Read the OV9650_VREF register first to avoid
corrupting the VREF high and low bits */
@@ -461,7 +461,7 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
*val = (i2c_data & OV9650_AWB_EN) >> 1;
- PDEBUG(DBG_V4L2_CID, "Read auto white balance %d", *val);
+ PDEBUG(D_V4L2, "Read auto white balance %d", *val);
return (err < 0) ? err : 0;
}
@@ -472,7 +472,7 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(DBG_V4L2_CID, "Set auto white balance to %d", val);
+ PDEBUG(D_V4L2, "Set auto white balance to %d", val);
err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
goto out;
@@ -491,7 +491,7 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
*val = (i2c_data & OV9650_AGC_EN) >> 2;
- PDEBUG(DBG_V4L2_CID, "Read auto gain control %d", *val);
+ PDEBUG(D_V4L2, "Read auto gain control %d", *val);
return (err < 0) ? err : 0;
}
@@ -502,7 +502,7 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(DBG_V4L2_CID, "Set auto gain control to %d", val);
+ PDEBUG(D_V4L2, "Set auto gain control to %d", val);
err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
goto out;
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h
index 2f29cb056f3..065632f0378 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.h
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h
@@ -1,7 +1,7 @@
/*
* Driver for the ov9650 sensor
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -121,7 +121,6 @@
/* Kernel module parameters */
extern int force_sensor;
extern int dump_sensor;
-extern unsigned int m5602_debug;
int ov9650_probe(struct sd *sd);
int ov9650_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c
index 08c015bde11..d17ac52566e 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.c
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.c
@@ -1,7 +1,7 @@
/*
* Driver for the po1030 sensor
*
- * Copyright (c) 2008 Erik Andren
+ * Copyright (c) 2008 Erik Andrén
* Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -82,7 +82,7 @@ int po1030_read_sensor(struct sd *sd, const u8 address,
for (i = 0; i < len; i++) {
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
- PDEBUG(DBG_TRACE, "Reading sensor register "
+ PDEBUG(D_CONF, "Reading sensor register "
"0x%x containing 0x%x ", address, *i2c_data);
}
return (err < 0) ? err : 0;
@@ -112,7 +112,7 @@ int po1030_write_sensor(struct sd *sd, const u8 address,
memcpy(p, sensor_urb_skeleton + 16, 4);
p[3] = i2c_data[i];
p += 4;
- PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+ PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
address, i2c_data[i]);
}
@@ -185,7 +185,7 @@ int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
&i2c_data, 1);
*val |= i2c_data;
- PDEBUG(DBG_V4L2_CID, "Exposure read as %d", *val);
+ PDEBUG(D_V4L2, "Exposure read as %d", *val);
out:
return (err < 0) ? err : 0;
}
@@ -196,10 +196,10 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
int err;
- PDEBUG(DBG_V4L2, "Set exposure to %d", val & 0xffff);
+ PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
i2c_data = ((val & 0xff00) >> 8);
- PDEBUG(DBG_V4L2, "Set exposure to high byte to 0x%x",
+ PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
i2c_data);
err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_H,
@@ -208,7 +208,7 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
goto out;
i2c_data = (val & 0xff);
- PDEBUG(DBG_V4L2, "Set exposure to low byte to 0x%x",
+ PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
i2c_data);
err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_M,
&i2c_data, 1);
@@ -226,7 +226,71 @@ int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
&i2c_data, 1);
*val = i2c_data;
- PDEBUG(DBG_V4L2_CID, "Read global gain %d", *val);
+ PDEBUG(D_V4L2, "Read global gain %d", *val);
+
+ return (err < 0) ? err : 0;
+}
+
+int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 i2c_data;
+ int err;
+
+ err = po1030_read_sensor(sd, PO1030_REG_CONTROL2,
+ &i2c_data, 1);
+
+ *val = (i2c_data >> 7) & 0x01 ;
+
+ PDEBUG(D_V4L2, "Read hflip %d", *val);
+
+ return (err < 0) ? err : 0;
+}
+
+int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 i2c_data;
+ int err;
+
+ PDEBUG(D_V4L2, "Set hflip %d", val);
+
+ i2c_data = (val & 0x01) << 7;
+
+ err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
+ &i2c_data, 1);
+
+ return (err < 0) ? err : 0;
+}
+
+int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 i2c_data;
+ int err;
+
+ err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
+ &i2c_data, 1);
+
+ *val = (i2c_data >> 6) & 0x01;
+
+ PDEBUG(D_V4L2, "Read vflip %d", *val);
+
+ return (err < 0) ? err : 0;
+}
+
+int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 i2c_data;
+ int err;
+
+ PDEBUG(D_V4L2, "Set vflip %d", val);
+
+ i2c_data = (val & 0x01) << 6;
+
+ err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
+ &i2c_data, 1);
return (err < 0) ? err : 0;
}
@@ -238,7 +302,7 @@ int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
int err;
i2c_data = val & 0xff;
- PDEBUG(DBG_V4L2, "Set global gain to %d", i2c_data);
+ PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
err = po1030_write_sensor(sd, PO1030_REG_GLOBALGAIN,
&i2c_data, 1);
return (err < 0) ? err : 0;
@@ -253,7 +317,7 @@ int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
err = po1030_read_sensor(sd, PO1030_REG_RED_GAIN,
&i2c_data, 1);
*val = i2c_data;
- PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
+ PDEBUG(D_V4L2, "Read red gain %d", *val);
return (err < 0) ? err : 0;
}
@@ -264,7 +328,7 @@ int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
int err;
i2c_data = val & 0xff;
- PDEBUG(DBG_V4L2, "Set red gain to %d", i2c_data);
+ PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
err = po1030_write_sensor(sd, PO1030_REG_RED_GAIN,
&i2c_data, 1);
return (err < 0) ? err : 0;
@@ -279,7 +343,7 @@ int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
err = po1030_read_sensor(sd, PO1030_REG_BLUE_GAIN,
&i2c_data, 1);
*val = i2c_data;
- PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
+ PDEBUG(D_V4L2, "Read blue gain %d", *val);
return (err < 0) ? err : 0;
}
@@ -290,7 +354,7 @@ int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
u8 i2c_data;
int err;
i2c_data = val & 0xff;
- PDEBUG(DBG_V4L2, "Set blue gain to %d", i2c_data);
+ PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
err = po1030_write_sensor(sd, PO1030_REG_BLUE_GAIN,
&i2c_data, 1);
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h
index 68f34c97bf4..a0b75ff61d7 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.h
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.h
@@ -1,8 +1,7 @@
/*
* Driver for the po1030 sensor.
- * This is probably a pixel plus sensor but we haven't identified it yet
*
- * Copyright (c) 2008 Erik Andren
+ * Copyright (c) 2008 Erik Andrén
* Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -109,10 +108,13 @@
#define PO1030_REG_YCONTRAST 0x74
#define PO1030_REG_YSATURATION 0x75
+#define PO1030_HFLIP (1 << 7)
+#define PO1030_VFLIP (1 << 6)
+
/*****************************************************************************/
#define PO1030_GLOBAL_GAIN_DEFAULT 0x12
-#define PO1030_EXPOSURE_DEFAULT 0xf0ff
+#define PO1030_EXPOSURE_DEFAULT 0x0085
#define PO1030_BLUE_GAIN_DEFAULT 0x40
#define PO1030_RED_GAIN_DEFAULT 0x40
@@ -121,7 +123,6 @@
/* Kernel module parameters */
extern int force_sensor;
extern int dump_sensor;
-extern unsigned int m5602_debug;
int po1030_probe(struct sd *sd);
int po1030_init(struct sd *sd);
@@ -142,6 +143,10 @@ int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
static struct m5602_sensor po1030 = {
.name = "PO1030",
@@ -152,7 +157,7 @@ static struct m5602_sensor po1030 = {
.init = po1030_init,
.power_down = po1030_power_down,
- .nctrls = 4,
+ .nctrls = 6,
.ctrls = {
{
{
@@ -160,7 +165,7 @@ static struct m5602_sensor po1030 = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "gain",
.minimum = 0x00,
- .maximum = 0xff,
+ .maximum = 0x4f,
.step = 0x1,
.default_value = PO1030_GLOBAL_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
@@ -173,7 +178,7 @@ static struct m5602_sensor po1030 = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "exposure",
.minimum = 0x00,
- .maximum = 0xffff,
+ .maximum = 0x02ff,
.step = 0x1,
.default_value = PO1030_EXPOSURE_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
@@ -206,8 +211,33 @@ static struct m5602_sensor po1030 = {
},
.set = po1030_set_blue_balance,
.get = po1030_get_blue_balance
+ }, {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = po1030_set_hflip,
+ .get = po1030_get_hflip
+ }, {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = po1030_set_vflip,
+ .get = po1030_get_vflip
}
},
+
.nmodes = 1,
.modes = {
{
@@ -381,7 +411,7 @@ static const unsigned char init_po1030[][4] =
/* Set the y window to 1 */
{SENSOR, PO1030_REG_WINDOWY_H, 0x00},
- {SENSOR, PO1030_REG_WINDOWX_L, 0x01},
+ {SENSOR, PO1030_REG_WINDOWY_L, 0x01},
{SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02},
{SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87},
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index 68202565325..14b1eac5b81 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -1,7 +1,7 @@
/*
* Driver for the s5k4aa sensor
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -117,7 +117,7 @@ int s5k4aa_read_sensor(struct sd *sd, const u8 address,
for (i = 0; (i < len) & !err; i++) {
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
- PDEBUG(DBG_TRACE, "Reading sensor register "
+ PDEBUG(D_CONF, "Reading sensor register "
"0x%x containing 0x%x ", address, *i2c_data);
}
out:
@@ -150,7 +150,7 @@ int s5k4aa_write_sensor(struct sd *sd, const u8 address,
memcpy(p, sensor_urb_skeleton + 16, 4);
p[3] = i2c_data[i];
p += 4;
- PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+ PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
address, i2c_data[i]);
}
@@ -248,7 +248,7 @@ int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
*val = data << 8;
err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
*val |= data;
- PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
+ PDEBUG(D_V4L2, "Read exposure %d", *val);
out:
return (err < 0) ? err : 0;
}
@@ -259,7 +259,7 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- PDEBUG(DBG_V4L2_CID, "Set exposure to %d", val);
+ PDEBUG(D_V4L2, "Set exposure to %d", val);
err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
@@ -285,7 +285,7 @@ int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
*val = (data & S5K4AA_RM_V_FLIP) >> 7;
- PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+ PDEBUG(D_V4L2, "Read vertical flip %d", *val);
out:
return (err < 0) ? err : 0;
@@ -297,7 +297,7 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+ PDEBUG(D_V4L2, "Set vertical flip to %d", val);
err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
@@ -341,7 +341,7 @@ int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
*val = (data & S5K4AA_RM_H_FLIP) >> 6;
- PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+ PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
out:
return (err < 0) ? err : 0;
}
@@ -352,7 +352,7 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d",
+ PDEBUG(D_V4L2, "Set horizontal flip to %d",
val);
err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
@@ -397,7 +397,7 @@ int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
*val = data;
- PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+ PDEBUG(D_V4L2, "Read gain %d", *val);
out:
return (err < 0) ? err : 0;
@@ -409,7 +409,7 @@ int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- PDEBUG(DBG_V4L2_CID, "Set gain to %d", val);
+ PDEBUG(D_V4L2, "Set gain to %d", val);
err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
goto out;
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
index bb7f7e3e90a..eaef67655af 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
@@ -1,7 +1,7 @@
/*
* Driver for the s5k4aa sensor
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -63,7 +63,6 @@
/* Kernel module parameters */
extern int force_sensor;
extern int dump_sensor;
-extern unsigned int m5602_debug;
int s5k4aa_probe(struct sd *sd);
int s5k4aa_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index b4b33c2d049..8988a728e0b 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -1,7 +1,7 @@
/*
* Driver for the s5k83a sensor
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -101,7 +101,7 @@ int s5k83a_read_sensor(struct sd *sd, const u8 address,
for (i = 0; i < len && !len; i++) {
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
- PDEBUG(DBG_TRACE, "Reading sensor register "
+ PDEBUG(D_CONF, "Reading sensor register "
"0x%x containing 0x%x ", address, *i2c_data);
}
@@ -135,7 +135,7 @@ int s5k83a_write_sensor(struct sd *sd, const u8 address,
memcpy(p, sensor_urb_skeleton + 16, 4);
p[3] = i2c_data[i];
p += 4;
- PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+ PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
address, i2c_data[i]);
}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
index 833708eb5a4..ee3ee9cfca1 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -1,7 +1,7 @@
/*
* Driver for the s5k83a sensor
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
@@ -41,8 +41,6 @@
/* Kernel module parameters */
extern int force_sensor;
extern int dump_sensor;
-extern unsigned int m5602_debug;
-
int s5k83a_probe(struct sd *sd);
int s5k83a_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_sensor.h b/drivers/media/video/gspca/m5602/m5602_sensor.h
index 930fcaab441..60c9a48e0c0 100644
--- a/drivers/media/video/gspca/m5602/m5602_sensor.h
+++ b/drivers/media/video/gspca/m5602/m5602_sensor.h
@@ -1,7 +1,7 @@
/*
* USB Driver for ALi m5602 based webcams
*
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
*
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index b561f7c4f06..eac245d7a75 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -50,7 +50,7 @@ struct sd {
__u8 sensor;
#define SENSOR_TAS5130A 0
-#define SENSOR_OTHER 1
+#define SENSOR_OM6802 1
};
/* V4L2 controls supported by the driver */
@@ -188,7 +188,7 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
- .default_value = 1,
+ .default_value = 0,
},
.set = sd_setwhitebalance,
.get = sd_getwhitebalance
@@ -261,6 +261,59 @@ static struct v4l2_pix_format vga_mode_t16[] = {
.priv = 0},
};
+/* sensor specific data */
+struct additional_sensor_data {
+ const __u8 data1[20];
+ const __u8 data2[18];
+ const __u8 data3[18];
+ const __u8 data4[4];
+ const __u8 data5[6];
+ const __u8 stream[4];
+};
+
+const static struct additional_sensor_data sensor_data[] = {
+ { /* TAS5130A */
+ .data1 =
+ {0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10,
+ 0xd4, 0xbb, 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
+ 0xd8, 0xc8, 0xd9, 0xfc},
+ .data2 =
+ {0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60,
+ 0xe4, 0xa8, 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
+ 0xe8, 0xe0},
+ .data3 =
+ {0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60,
+ 0xcb, 0xa8, 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
+ 0xcf, 0xe0},
+ .data4 = /* Freq (50/60Hz). Splitted for test purpose */
+ {0x66, 0x00, 0xa8, 0xe8},
+ .data5 =
+ {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
+ .stream =
+ {0x0b, 0x04, 0x0a, 0x40},
+ },
+ { /* OM6802 */
+ .data1 =
+ {0xd0, 0xc2, 0xd1, 0x28, 0xd2, 0x0f, 0xd3, 0x22,
+ 0xd4, 0xcd, 0xd5, 0x27, 0xd6, 0x2c, 0xd7, 0x06,
+ 0xd8, 0xb3, 0xd9, 0xfc},
+ .data2 =
+ {0xe0, 0x80, 0xe1, 0xff, 0xe2, 0xff, 0xe3, 0x80,
+ 0xe4, 0xff, 0xe5, 0xff, 0xe6, 0x80, 0xe7, 0xff,
+ 0xe8, 0xff},
+ .data3 =
+ {0xc7, 0x80, 0xc8, 0xff, 0xc9, 0xff, 0xca, 0x80,
+ 0xcb, 0xff, 0xcc, 0xff, 0xcd, 0x80, 0xce, 0xff,
+ 0xcf, 0xff},
+ .data4 = /*Freq (50/60Hz). Splitted for test purpose */
+ {0x66, 0xca, 0xa8, 0xf0 },
+ .data5 = /* this could be removed later */
+ {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
+ .stream =
+ {0x0b, 0x04, 0x0a, 0x78},
+ }
+};
+
#define MAX_EFFECTS 7
/* easily done by soft, this table could be removed,
* i keep it here just in case */
@@ -365,6 +418,8 @@ static const __u8 tas5130a_sensor_init[][8] = {
{},
};
+static __u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
+
/* read 1 byte */
static int reg_r(struct gspca_dev *gspca_dev,
__u16 index)
@@ -385,12 +440,12 @@ static void reg_w(struct gspca_dev *gspca_dev,
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index,
NULL, 0, 500);
}
-static void i2c_w(struct gspca_dev *gspca_dev,
+static void reg_w_buf(struct gspca_dev *gspca_dev,
const __u8 *buffer, __u16 len)
{
if (len <= USB_BUF_SZ) {
@@ -398,7 +453,7 @@ static void i2c_w(struct gspca_dev *gspca_dev,
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x01, 0,
gspca_dev->usb_buf, len, 500);
} else {
@@ -409,14 +464,15 @@ static void i2c_w(struct gspca_dev *gspca_dev,
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x01, 0,
tmpbuf, len, 500);
kfree(tmpbuf);
}
}
-static void other_sensor_init(struct gspca_dev *gspca_dev)
+/* Reported as OM6802*/
+static void om6802_sensor_init(struct gspca_dev *gspca_dev)
{
int i;
const __u8 *p;
@@ -436,19 +492,32 @@ static void other_sensor_init(struct gspca_dev *gspca_dev)
0x90, 0x24,
0x91, 0xb2,
0x82, 0x32,
- 0xfd, 0x00,
- 0xfd, 0x01,
0xfd, 0x41,
0x00 /* table end */
};
+ reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
+ msleep(5);
+ i = 4;
+ while (--i < 0) {
+ byte = reg_r(gspca_dev, 0x0060);
+ if (!(byte & 0x01))
+ break;
+ msleep(100);
+ }
+ byte = reg_r(gspca_dev, 0x0063);
+ if (byte != 0x17) {
+ err("Bad sensor reset %02x", byte);
+ /* continue? */
+ }
+
p = sensor_init;
while (*p != 0) {
val[1] = *p++;
val[3] = *p++;
if (*p == 0)
reg_w(gspca_dev, 0x3c80);
- i2c_w(gspca_dev, val, sizeof val);
+ reg_w_buf(gspca_dev, val, sizeof val);
i = 4;
while (--i >= 0) {
msleep(15);
@@ -457,7 +526,8 @@ static void other_sensor_init(struct gspca_dev *gspca_dev)
break;
}
}
- reg_w(gspca_dev, 0x3c80);
+ msleep(15);
+ reg_w(gspca_dev, 0x3c80);
}
/* this function is called at probe time */
@@ -485,12 +555,75 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned int brightness;
+ __u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
+
+ brightness = sd->brightness;
+ if (brightness < 7) {
+ set6[1] = 0x26;
+ set6[3] = 0x70 - brightness * 0x10;
+ } else {
+ set6[3] = 0x00 + ((brightness - 7) * 0x10);
+ }
+
+ reg_w_buf(gspca_dev, set6, sizeof set6);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned int contrast = sd->contrast;
+ __u16 reg_to_write;
+
+ if (contrast < 7)
+ reg_to_write = 0x8ea9 - contrast * 0x200;
+ else
+ reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
+
+ reg_w(gspca_dev, reg_to_write);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u16 reg_to_write;
+
+ reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */
+ reg_w(gspca_dev, reg_to_write);
+}
+
static void setgamma(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
- i2c_w(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
+ reg_w_buf(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
+}
+
+static void setwhitebalance(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ __u8 white_balance[8] =
+ {0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38};
+
+ if (sd->whitebalance)
+ white_balance[7] = 0x3c;
+
+ reg_w_buf(gspca_dev, white_balance, sizeof white_balance);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u16 reg_to_write;
+
+ reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
+
+ reg_w(gspca_dev, reg_to_write);
}
/* this function is called at probe and resume time */
@@ -511,8 +644,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
static const __u8 n2[] =
{0x08, 0x00};
- static const __u8 nset[] =
- { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
static const __u8 n3[] =
{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
static const __u8 n4[] =
@@ -525,51 +656,29 @@ static int sd_init(struct gspca_dev *gspca_dev)
0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
- static const __u8 nset4[] = {
- 0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
- 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
- 0xe8, 0xe0
- };
- /* ojo puede ser 0xe6 en vez de 0xe9 */
- static const __u8 nset2[] = {
- 0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
- 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
- 0xd8, 0xc8, 0xd9, 0xfc
- };
- static const __u8 missing[] =
- { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
- static const __u8 nset3[] = {
- 0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
- 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
- 0xcf, 0xe0
- };
- static const __u8 nset5[] =
- { 0x8f, 0x24, 0xc3, 0x00 }; /* bright */
- static const __u8 nset7[4] =
- { 0x66, 0xca, 0xa8, 0xf8 }; /* 50/60 Hz */
static const __u8 nset9[4] =
{ 0x0b, 0x04, 0x0a, 0x78 };
static const __u8 nset8[6] =
{ 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
- static const __u8 nset10[6] =
- { 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
byte = reg_r(gspca_dev, 0x06);
test_byte = reg_r(gspca_dev, 0x07);
if (byte == 0x08 && test_byte == 0x07) {
- PDEBUG(D_CONF, "other sensor");
- sd->sensor = SENSOR_OTHER;
+ PDEBUG(D_CONF, "sensor om6802");
+ sd->sensor = SENSOR_OM6802;
+ } else if (byte == 0x08 && test_byte == 0x01) {
+ PDEBUG(D_CONF, "sensor tas5130a");
+ sd->sensor = SENSOR_TAS5130A;
} else {
- PDEBUG(D_CONF, "sensor %02x %02x", byte, test_byte);
+ PDEBUG(D_CONF, "unknown sensor %02x %02x", byte, test_byte);
sd->sensor = SENSOR_TAS5130A;
}
- i2c_w(gspca_dev, n1, sizeof n1);
+ reg_w_buf(gspca_dev, n1, sizeof n1);
test_byte = 0;
i = 5;
while (--i >= 0) {
- i2c_w(gspca_dev, nset, sizeof nset);
- msleep(5);
+ reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
test_byte = reg_r(gspca_dev, 0x0063);
msleep(100);
if (test_byte == 0x17)
@@ -580,7 +689,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* return -EIO; */
/*fixme: test - continue */
}
- i2c_w(gspca_dev, n2, sizeof n2);
+ reg_w_buf(gspca_dev, n2, sizeof n2);
i = 0;
while (read_indexs[i] != 0x00) {
@@ -590,56 +699,50 @@ static int sd_init(struct gspca_dev *gspca_dev)
i++;
}
- i2c_w(gspca_dev, n3, sizeof n3);
- i2c_w(gspca_dev, n4, sizeof n4);
+ reg_w_buf(gspca_dev, n3, sizeof n3);
+ reg_w_buf(gspca_dev, n4, sizeof n4);
reg_r(gspca_dev, 0x0080);
reg_w(gspca_dev, 0x2c80);
- i2c_w(gspca_dev, nset2, sizeof nset2);
- i2c_w(gspca_dev, nset3, sizeof nset3);
- i2c_w(gspca_dev, nset4, sizeof nset4);
+
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data1,
+ sizeof sensor_data[sd->sensor].data1);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
+ sizeof sensor_data[sd->sensor].data3);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
+ sizeof sensor_data[sd->sensor].data2);
+
reg_w(gspca_dev, 0x3880);
reg_w(gspca_dev, 0x3880);
reg_w(gspca_dev, 0x338e);
- i2c_w(gspca_dev, nset5, sizeof nset5);
- reg_w(gspca_dev, 0x00a9);
- setgamma(gspca_dev);
- reg_w(gspca_dev, 0x86bb);
- reg_w(gspca_dev, 0x4aa6);
- i2c_w(gspca_dev, missing, sizeof missing);
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setgamma(gspca_dev);
+ setcolors(gspca_dev);
+ setsharpness(gspca_dev);
+ setwhitebalance(gspca_dev);
- reg_w(gspca_dev, 0x2087);
+ reg_w(gspca_dev, 0x2087); /* tied to white balance? */
reg_w(gspca_dev, 0x2088);
reg_w(gspca_dev, 0x2089);
- i2c_w(gspca_dev, nset7, sizeof nset7);
- i2c_w(gspca_dev, nset10, sizeof nset10);
- i2c_w(gspca_dev, nset8, sizeof nset8);
- i2c_w(gspca_dev, nset9, sizeof nset9);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
+ sizeof sensor_data[sd->sensor].data4);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data5,
+ sizeof sensor_data[sd->sensor].data5);
+ reg_w_buf(gspca_dev, nset8, sizeof nset8);
+ reg_w_buf(gspca_dev, nset9, sizeof nset9);
reg_w(gspca_dev, 0x2880);
- i2c_w(gspca_dev, nset2, sizeof nset2);
- i2c_w(gspca_dev, nset3, sizeof nset3);
- i2c_w(gspca_dev, nset4, sizeof nset4);
-
- return 0;
-}
-
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- unsigned int brightness;
- __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x00 };
- brightness = sd->brightness;
- if (brightness < 7) {
- set6[3] = 0x70 - brightness * 0x10;
- } else {
- set6[1] = 0x24;
- set6[3] = 0x00 + ((brightness - 7) * 0x10);
- }
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data1,
+ sizeof sensor_data[sd->sensor].data1);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
+ sizeof sensor_data[sd->sensor].data3);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
+ sizeof sensor_data[sd->sensor].data2);
- i2c_w(gspca_dev, set6, sizeof set6);
+ return 0;
}
static void setflip(struct gspca_dev *gspca_dev)
@@ -651,14 +754,15 @@ static void setflip(struct gspca_dev *gspca_dev)
if (sd->mirror)
flipcmd[3] = 0x01;
- i2c_w(gspca_dev, flipcmd, sizeof flipcmd);
+ reg_w_buf(gspca_dev, flipcmd, sizeof flipcmd);
}
static void seteffect(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- i2c_w(gspca_dev, effects_table[sd->effect], sizeof effects_table[0]);
+ reg_w_buf(gspca_dev, effects_table[sd->effect],
+ sizeof effects_table[0]);
if (sd->effect == 1 || sd->effect == 5) {
PDEBUG(D_CONF,
"This effect have been disabled for webcam \"safety\"");
@@ -671,19 +775,6 @@ static void seteffect(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0xfaa6);
}
-static void setwhitebalance(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- __u8 white_balance[8] =
- { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
-
- if (sd->whitebalance == 1)
- white_balance[7] = 0x3c;
-
- i2c_w(gspca_dev, white_balance, sizeof white_balance);
-}
-
static void setlightfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -692,52 +783,46 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
if (sd->freq == 2) /* 60hz */
freq[1] = 0x00;
- i2c_w(gspca_dev, freq, sizeof freq);
+ reg_w_buf(gspca_dev, freq, sizeof freq);
}
-static void setcontrast(struct gspca_dev *gspca_dev)
+/* Is this really needed?
+ * i added some module parameters for test with some users */
+static void poll_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- unsigned int contrast = sd->contrast;
- __u16 reg_to_write;
-
- if (contrast < 7)
- reg_to_write = 0x8ea9 - (0x200 * contrast);
- else
- reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
-
- reg_w(gspca_dev, reg_to_write);
-}
-
-static void setcolors(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- __u16 reg_to_write;
-
- reg_to_write = 0xc0bb + sd->colors * 0x100;
- reg_w(gspca_dev, reg_to_write);
-}
-
-static void setsharpness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- __u16 reg_to_write;
-
- reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
-
- reg_w(gspca_dev, reg_to_write);
+ static const __u8 poll1[] =
+ {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
+ 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
+ 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
+ 0x60, 0x14};
+ static const __u8 poll2[] =
+ {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
+ 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
+ static const __u8 poll3[] =
+ {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
+ static const __u8 poll4[] =
+ {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
+ 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
+ 0xc2, 0x80, 0xc3, 0x10};
+
+ if (sd->sensor != SENSOR_TAS5130A) {
+ PDEBUG(D_STREAM, "[Sensor requires polling]");
+ reg_w_buf(gspca_dev, poll1, sizeof poll1);
+ reg_w_buf(gspca_dev, poll2, sizeof poll2);
+ reg_w_buf(gspca_dev, poll3, sizeof poll3);
+ reg_w_buf(gspca_dev, poll4, sizeof poll4);
+ }
}
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, mode;
- static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
__u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
static const __u8 t3[] =
{ 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
- static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
switch (mode) {
@@ -760,25 +845,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
if (sd->sensor == SENSOR_TAS5130A) {
i = 0;
while (tas5130a_sensor_init[i][0] != 0) {
- i2c_w(gspca_dev, tas5130a_sensor_init[i],
+ reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
sizeof tas5130a_sensor_init[0]);
i++;
}
reg_w(gspca_dev, 0x3c80);
/* just in case and to keep sync with logs (for mine) */
- i2c_w(gspca_dev, tas5130a_sensor_init[3],
+ reg_w_buf(gspca_dev, tas5130a_sensor_init[3],
sizeof tas5130a_sensor_init[0]);
reg_w(gspca_dev, 0x3c80);
} else {
- other_sensor_init(gspca_dev);
+ om6802_sensor_init(gspca_dev);
}
- /* just in case and to keep sync with logs (for mine) */
- i2c_w(gspca_dev, t1, sizeof t1);
- i2c_w(gspca_dev, t2, sizeof t2);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
+ sizeof sensor_data[sd->sensor].data4);
reg_r(gspca_dev, 0x0012);
- i2c_w(gspca_dev, t3, sizeof t3);
+ reg_w_buf(gspca_dev, t2, sizeof t2);
+ reg_w_buf(gspca_dev, t3, sizeof t3);
reg_w(gspca_dev, 0x0013);
- i2c_w(gspca_dev, t4, sizeof t4);
+ msleep(15);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
+ sizeof sensor_data[sd->sensor].stream);
+ poll_sensor(gspca_dev);
+
/* restart on each start, just in case, sometimes regs goes wrong
* when using controls from app */
setbrightness(gspca_dev);
@@ -787,6 +876,19 @@ static int sd_start(struct gspca_dev *gspca_dev)
return 0;
}
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
+ sizeof sensor_data[sd->sensor].stream);
+ msleep(20);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
+ sizeof sensor_data[sd->sensor].stream);
+ msleep(20);
+ reg_w(gspca_dev, 0x0309);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -1036,6 +1138,7 @@ static const struct sd_desc sd_desc = {
.config = sd_config,
.init = sd_init,
.start = sd_start,
+ .stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
};
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index aeaa13f6cb3..d36485023b6 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1211,6 +1211,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
+ /* Turn off the output signal. The mpeg decoder is not yet
+ active so without this you would get a green image until the
+ mpeg decoder becomes active. */
+ ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
}
/* clear interrupt mask, effectively disabling interrupts */
@@ -1330,6 +1334,10 @@ int ivtv_init_on_first_open(struct ivtv *itv)
ivtv_s_frequency(NULL, &fh, &vf);
if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
+ /* Turn on the TV-out: ivtv_init_mpeg_decoder() initializes
+ the mpeg decoder so now the saa7127 receives a proper
+ signal. */
+ ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
ivtv_init_mpeg_decoder(itv);
}
ivtv_s_std(NULL, &fh, &itv->tuner_std);
@@ -1366,6 +1374,10 @@ static void ivtv_remove(struct pci_dev *pci_dev)
/* Stop all decoding */
IVTV_DEBUG_INFO("Stopping decoding\n");
+
+ /* Turn off the TV-out */
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+ ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
if (atomic_read(&itv->decoding) > 0) {
int type;
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index bc29436e8a3..3733b2afec5 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -55,6 +55,7 @@
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/byteorder.h>
#include <linux/dvb/video.h>
#include <linux/dvb/audio.h>
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index b7457fc60ba..1c404e454a3 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -600,13 +600,14 @@ retry:
since we may get here before the stream has been fully set-up */
if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
while (count >= itv->dma_data_req_size) {
- if (!ivtv_yuv_udma_stream_frame (itv, (void __user *)user_buf)) {
- bytes_written += itv->dma_data_req_size;
- user_buf += itv->dma_data_req_size;
- count -= itv->dma_data_req_size;
- } else {
- break;
- }
+ rc = ivtv_yuv_udma_stream_frame(itv, (void __user *)user_buf);
+
+ if (rc < 0)
+ return rc;
+
+ bytes_written += itv->dma_data_req_size;
+ user_buf += itv->dma_data_req_size;
+ count -= itv->dma_data_req_size;
}
if (count == 0) {
IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 24700c211d5..41dbbe9621a 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -726,6 +726,7 @@ int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg)
{
return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg);
}
+EXPORT_SYMBOL(ivtv_saa7127);
int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg)
{
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 8696527ab13..4bae38d21ef 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -509,7 +509,6 @@ static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_
static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv_open_id *id = fh;
- struct ivtv *itv = id->itv;
s32 w = fmt->fmt.pix.width;
s32 h = fmt->fmt.pix.height;
int field = fmt->fmt.pix.field;
@@ -517,7 +516,22 @@ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format
w = min(w, 720);
w = max(w, 2);
- h = min(h, itv->is_out_50hz ? 576 : 480);
+ /* Why can the height be 576 even when the output is NTSC?
+
+ Internally the buffers of the PVR350 are always set to 720x576. The
+ decoded video frame will always be placed in the top left corner of
+ this buffer. For any video which is not 720x576, the buffer will
+ then be cropped to remove the unused right and lower areas, with
+ the remaining image being scaled by the hardware to fit the display
+ area. The video can be scaled both up and down, so a 720x480 video
+ can be displayed full-screen on PAL and a 720x576 video can be
+ displayed without cropping on NTSC.
+
+ Note that the scaling only occurs on the video stream, the osd
+ resolution is locked to the broadcast standard and not scaled.
+
+ Thanks to Ian Armstrong for this explanation. */
+ h = min(h, 576);
h = max(h, 2);
if (id->type == IVTV_DEC_STREAM_TYPE_YUV)
fmt->fmt.pix.field = field;
@@ -1742,12 +1756,12 @@ static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
return 0;
}
-static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
+static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct video_device *vfd = video_devdata(filp);
struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
- int ret;
+ long ret;
/* Filter dvb ioctls that cannot be handled by the v4l ioctl framework */
switch (cmd) {
@@ -1816,20 +1830,19 @@ static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct f
if (ivtv_debug & IVTV_DBGFLG_IOCTL)
vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
- ret = video_ioctl2(inode, filp, cmd, arg);
+ ret = __video_ioctl2(filp, cmd, arg);
vfd->debug = 0;
return ret;
}
-int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
struct ivtv *itv = id->itv;
- int res;
+ long res;
mutex_lock(&itv->serialize_lock);
- res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg);
+ res = ivtv_serialized_ioctl(itv, filp, cmd, arg);
mutex_unlock(&itv->serialize_lock);
return res;
}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h
index 70188588b4f..58f003412af 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -30,7 +30,6 @@ void ivtv_set_funcs(struct video_device *vdev);
int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std);
int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
int ivtv_s_input(struct file *file, void *fh, unsigned int inp);
-int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg);
+long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
#endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 5bbf31e3930..9b7aa79eb26 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -48,7 +48,7 @@ static const struct file_operations ivtv_v4l2_enc_fops = {
.read = ivtv_v4l2_read,
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
- .ioctl = ivtv_v4l2_ioctl,
+ .unlocked_ioctl = ivtv_v4l2_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_enc_poll,
@@ -59,7 +59,7 @@ static const struct file_operations ivtv_v4l2_dec_fops = {
.read = ivtv_v4l2_read,
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
- .ioctl = ivtv_v4l2_ioctl,
+ .unlocked_ioctl = ivtv_v4l2_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_dec_poll,
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 8a4a150b12f..921e281876f 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -48,6 +48,7 @@
#endif
#include "ivtv-driver.h"
+#include "ivtv-i2c.h"
#include "ivtv-udma.h"
#include "ivtv-mailbox.h"
@@ -894,11 +895,16 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
switch (blank_mode) {
case FB_BLANK_UNBLANK:
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
+ ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
break;
case FB_BLANK_NORMAL:
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_VSYNC_SUSPEND:
+ ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
+ ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+ break;
case FB_BLANK_POWERDOWN:
+ ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
break;
}
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index 2fd4b4a44aa..bae2d2beb70 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -33,27 +33,20 @@
* V1.1 Gerard v.d. Horst Added some debugoutput, reset the video-standard
*/
-#ifndef __KERNEL__
-#define __KERNEL__
-#endif
-
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include "ks0127.h"
-
#include <linux/i2c.h>
#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include "ks0127.h"
-#define dprintk if (debug) printk
-
-/* i2c identification */
-#define I2C_KS0127_ADDON 0xD8
-#define I2C_KS0127_ONBOARD 0xDA
+MODULE_DESCRIPTION("KS0127 video decoder driver");
+MODULE_AUTHOR("Ryan Drake");
+MODULE_LICENSE("GPL");
#define KS_TYPE_UNKNOWN 0
#define KS_TYPE_0122S 1
@@ -204,8 +197,6 @@ struct adjust {
};
struct ks0127 {
- struct i2c_client *client;
- unsigned char addr;
int format_width;
int format_height;
int cap_width;
@@ -220,16 +211,18 @@ static int debug; /* insmod parameter */
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug output");
-MODULE_LICENSE("GPL");
static u8 reg_defaults[64];
-
-
static void init_reg_defaults(void)
{
+ static int initialized;
u8 *table = reg_defaults;
+ if (initialized)
+ return;
+ initialized = 1;
+
table[KS_CMDA] = 0x2c; /* VSE=0, CCIR 601, autodetect standard */
table[KS_CMDB] = 0x12; /* VALIGN=0, AGC control and input */
table[KS_CMDC] = 0x00; /* Test options */
@@ -308,50 +301,53 @@ static void init_reg_defaults(void)
* An explanation from kayork@mail.utexas.edu:
*
* During I2C reads, the KS0127 only samples for a stop condition
- * during the place where the acknoledge bit should be. Any standard
+ * during the place where the acknowledge bit should be. Any standard
* I2C implementation (correctly) throws in another clock transition
* at the 9th bit, and the KS0127 will not recognize the stop condition
* and will continue to clock out data.
*
* So we have to do the read ourself. Big deal.
- workaround in i2c-algo-bit
+ * workaround in i2c-algo-bit
*/
-static u8 ks0127_read(struct ks0127 *ks, u8 reg)
+static u8 ks0127_read(struct i2c_client *c, u8 reg)
{
- struct i2c_client *c = ks->client;
char val = 0;
struct i2c_msg msgs[] = {
- {c->addr, 0, sizeof(reg), &reg},
- {c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val}};
+ { c->addr, 0, sizeof(reg), &reg },
+ { c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val }
+ };
int ret;
ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs))
- dprintk("ks0127_write error\n");
+ v4l_dbg(1, debug, c, "read error\n");
return val;
}
-static void ks0127_write(struct ks0127 *ks, u8 reg, u8 val)
+static void ks0127_write(struct i2c_client *c, u8 reg, u8 val)
{
- char msg[] = {reg, val};
+ struct ks0127 *ks = i2c_get_clientdata(c);
+ char msg[] = { reg, val };
- if (i2c_master_send(ks->client, msg, sizeof(msg)) != sizeof(msg))
- dprintk("ks0127_write error\n");
+ if (i2c_master_send(c, msg, sizeof(msg)) != sizeof(msg))
+ v4l_dbg(1, debug, c, "write error\n");
ks->regs[reg] = val;
}
/* generic bit-twiddling */
-static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
+static void ks0127_and_or(struct i2c_client *client, u8 reg, u8 and_v, u8 or_v)
{
+ struct ks0127 *ks = i2c_get_clientdata(client);
+
u8 val = ks->regs[reg];
val = (val & and_v) | or_v;
- ks0127_write(ks, reg, val);
+ ks0127_write(client, reg, val);
}
@@ -359,73 +355,69 @@ static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
/****************************************************************************
* ks0127 private api
****************************************************************************/
-static void ks0127_reset(struct ks0127* ks)
+static void ks0127_reset(struct i2c_client *c)
{
- int i;
+ struct ks0127 *ks = i2c_get_clientdata(c);
u8 *table = reg_defaults;
+ int i;
ks->ks_type = KS_TYPE_UNKNOWN;
- dprintk("ks0127: reset\n");
+ v4l_dbg(1, debug, c, "reset\n");
msleep(1);
/* initialize all registers to known values */
/* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
- for(i = 1; i < 33; i++)
- ks0127_write(ks, i, table[i]);
+ for (i = 1; i < 33; i++)
+ ks0127_write(c, i, table[i]);
- for(i = 35; i < 40; i++)
- ks0127_write(ks, i, table[i]);
+ for (i = 35; i < 40; i++)
+ ks0127_write(c, i, table[i]);
- for(i = 41; i < 56; i++)
- ks0127_write(ks, i, table[i]);
+ for (i = 41; i < 56; i++)
+ ks0127_write(c, i, table[i]);
- for(i = 58; i < 64; i++)
- ks0127_write(ks, i, table[i]);
+ for (i = 58; i < 64; i++)
+ ks0127_write(c, i, table[i]);
- if ((ks0127_read(ks, KS_STAT) & 0x80) == 0) {
+ if ((ks0127_read(c, KS_STAT) & 0x80) == 0) {
ks->ks_type = KS_TYPE_0122S;
- dprintk("ks0127: ks0122s Found\n");
+ v4l_dbg(1, debug, c, "ks0122s found\n");
return;
}
- switch(ks0127_read(ks, KS_CMDE) & 0x0f) {
-
+ switch (ks0127_read(c, KS_CMDE) & 0x0f) {
case 0:
ks->ks_type = KS_TYPE_0127;
- dprintk("ks0127: ks0127 found\n");
+ v4l_dbg(1, debug, c, "ks0127 found\n");
break;
case 9:
ks->ks_type = KS_TYPE_0127B;
- dprintk("ks0127: ks0127B Revision A found\n");
+ v4l_dbg(1, debug, c, "ks0127B Revision A found\n");
break;
default:
- dprintk("ks0127: unknown revision\n");
+ v4l_dbg(1, debug, c, "unknown revision\n");
break;
}
}
-static int ks0127_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static int ks0127_command(struct i2c_client *c, unsigned cmd, void *arg)
{
- struct ks0127 *ks = i2c_get_clientdata(client);
-
- int *iarg = (int*)arg;
-
+ struct ks0127 *ks = i2c_get_clientdata(c);
+ int *iarg = (int *)arg;
int status;
if (!ks)
return -ENODEV;
switch (cmd) {
-
case DECODER_INIT:
- dprintk("ks0127: command DECODER_INIT\n");
- ks0127_reset(ks);
+ v4l_dbg(1, debug, c, "DECODER_INIT\n");
+ ks0127_reset(c);
break;
case DECODER_SET_INPUT:
@@ -436,161 +428,160 @@ static int ks0127_command(struct i2c_client *client,
case KS_INPUT_COMPOSITE_4:
case KS_INPUT_COMPOSITE_5:
case KS_INPUT_COMPOSITE_6:
- dprintk("ks0127: command DECODER_SET_INPUT %d: "
- "Composite\n", *iarg);
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_INPUT %d: Composite\n", *iarg);
/* autodetect 50/60 Hz */
- ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ ks0127_and_or(c, KS_CMDA, 0xfc, 0x00);
/* VSE=0 */
- ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
+ ks0127_and_or(c, KS_CMDA, ~0x40, 0x00);
/* set input line */
- ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
+ ks0127_and_or(c, KS_CMDB, 0xb0, *iarg);
/* non-freerunning mode */
- ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
+ ks0127_and_or(c, KS_CMDC, 0x70, 0x0a);
/* analog input */
- ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
+ ks0127_and_or(c, KS_CMDD, 0x03, 0x00);
/* enable chroma demodulation */
- ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+ ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
/* chroma trap, HYBWR=1 */
- ks0127_and_or(ks, KS_LUMA, 0x00,
+ ks0127_and_or(c, KS_LUMA, 0x00,
(reg_defaults[KS_LUMA])|0x0c);
/* scaler fullbw, luma comb off */
- ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+ ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
/* manual chroma comb .25 .5 .25 */
- ks0127_and_or(ks, KS_VERTIC, 0x0f, 0x90);
+ ks0127_and_or(c, KS_VERTIC, 0x0f, 0x90);
/* chroma path delay */
- ks0127_and_or(ks, KS_CHROMB, 0x0f, 0x90);
+ ks0127_and_or(c, KS_CHROMB, 0x0f, 0x90);
- ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
- ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
- ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
- ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+ ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
+ ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
+ ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+ ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
break;
case KS_INPUT_SVIDEO_1:
case KS_INPUT_SVIDEO_2:
case KS_INPUT_SVIDEO_3:
- dprintk("ks0127: command DECODER_SET_INPUT %d: "
- "S-Video\n", *iarg);
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_INPUT %d: S-Video\n", *iarg);
/* autodetect 50/60 Hz */
- ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ ks0127_and_or(c, KS_CMDA, 0xfc, 0x00);
/* VSE=0 */
- ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
+ ks0127_and_or(c, KS_CMDA, ~0x40, 0x00);
/* set input line */
- ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
+ ks0127_and_or(c, KS_CMDB, 0xb0, *iarg);
/* non-freerunning mode */
- ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
+ ks0127_and_or(c, KS_CMDC, 0x70, 0x0a);
/* analog input */
- ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
+ ks0127_and_or(c, KS_CMDD, 0x03, 0x00);
/* enable chroma demodulation */
- ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
- ks0127_and_or(ks, KS_LUMA, 0x00,
+ ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
+ ks0127_and_or(c, KS_LUMA, 0x00,
reg_defaults[KS_LUMA]);
/* disable luma comb */
- ks0127_and_or(ks, KS_VERTIA, 0x08,
+ ks0127_and_or(c, KS_VERTIA, 0x08,
(reg_defaults[KS_VERTIA]&0xf0)|0x01);
- ks0127_and_or(ks, KS_VERTIC, 0x0f,
+ ks0127_and_or(c, KS_VERTIC, 0x0f,
reg_defaults[KS_VERTIC]&0xf0);
- ks0127_and_or(ks, KS_CHROMB, 0x0f,
+ ks0127_and_or(c, KS_CHROMB, 0x0f,
reg_defaults[KS_CHROMB]&0xf0);
- ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
- ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
- ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
- ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+ ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
+ ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
+ ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+ ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
break;
case KS_INPUT_YUV656:
- dprintk("ks0127: command DECODER_SET_INPUT 15: "
- "YUV656\n");
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_INPUT 15: YUV656\n");
if (ks->norm == VIDEO_MODE_NTSC ||
ks->norm == KS_STD_PAL_M)
/* force 60 Hz */
- ks0127_and_or(ks, KS_CMDA, 0xfc, 0x03);
+ ks0127_and_or(c, KS_CMDA, 0xfc, 0x03);
else
/* force 50 Hz */
- ks0127_and_or(ks, KS_CMDA, 0xfc, 0x02);
+ ks0127_and_or(c, KS_CMDA, 0xfc, 0x02);
- ks0127_and_or(ks, KS_CMDA, 0xff, 0x40); /* VSE=1 */
+ ks0127_and_or(c, KS_CMDA, 0xff, 0x40); /* VSE=1 */
/* set input line and VALIGN */
- ks0127_and_or(ks, KS_CMDB, 0xb0, (*iarg | 0x40));
+ ks0127_and_or(c, KS_CMDB, 0xb0, (*iarg | 0x40));
/* freerunning mode, */
/* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/
- ks0127_and_or(ks, KS_CMDC, 0x70, 0x87);
+ ks0127_and_or(c, KS_CMDC, 0x70, 0x87);
/* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
- ks0127_and_or(ks, KS_CMDD, 0x03, 0x08);
+ ks0127_and_or(c, KS_CMDD, 0x03, 0x08);
/* disable chroma demodulation */
- ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x30);
+ ks0127_and_or(c, KS_CTRACK, 0xcf, 0x30);
/* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
- ks0127_and_or(ks, KS_LUMA, 0x00, 0x71);
- ks0127_and_or(ks, KS_VERTIC, 0x0f,
+ ks0127_and_or(c, KS_LUMA, 0x00, 0x71);
+ ks0127_and_or(c, KS_VERTIC, 0x0f,
reg_defaults[KS_VERTIC]&0xf0);
/* scaler fullbw, luma comb off */
- ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+ ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
- ks0127_and_or(ks, KS_CHROMB, 0x0f,
+ ks0127_and_or(c, KS_CHROMB, 0x0f,
reg_defaults[KS_CHROMB]&0xf0);
- ks0127_and_or(ks, KS_CON, 0x00, 0x00);
- ks0127_and_or(ks, KS_BRT, 0x00, 32); /* spec: 34 */
+ ks0127_and_or(c, KS_CON, 0x00, 0x00);
+ ks0127_and_or(c, KS_BRT, 0x00, 32); /* spec: 34 */
/* spec: 229 (e5) */
- ks0127_and_or(ks, KS_SAT, 0x00, 0xe8);
- ks0127_and_or(ks, KS_HUE, 0x00, 0);
+ ks0127_and_or(c, KS_SAT, 0x00, 0xe8);
+ ks0127_and_or(c, KS_HUE, 0x00, 0);
- ks0127_and_or(ks, KS_UGAIN, 0x00, 238);
- ks0127_and_or(ks, KS_VGAIN, 0x00, 0x00);
+ ks0127_and_or(c, KS_UGAIN, 0x00, 238);
+ ks0127_and_or(c, KS_VGAIN, 0x00, 0x00);
/*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
- ks0127_and_or(ks, KS_UVOFFH, 0x00, 0x4f);
- ks0127_and_or(ks, KS_UVOFFL, 0x00, 0x00);
+ ks0127_and_or(c, KS_UVOFFH, 0x00, 0x4f);
+ ks0127_and_or(c, KS_UVOFFL, 0x00, 0x00);
break;
default:
- dprintk("ks0127: command DECODER_SET_INPUT: "
- "Unknown input %d\n", *iarg);
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_INPUT: Unknown input %d\n", *iarg);
break;
}
/* hack: CDMLPF sometimes spontaneously switches on; */
/* force back off */
- ks0127_write(ks, KS_DEMOD, reg_defaults[KS_DEMOD]);
+ ks0127_write(c, KS_DEMOD, reg_defaults[KS_DEMOD]);
break;
case DECODER_SET_OUTPUT:
switch(*iarg) {
case KS_OUTPUT_YUV656E:
- dprintk("ks0127: command DECODER_SET_OUTPUT: "
- "OUTPUT_YUV656E (Missing)\n");
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_OUTPUT: OUTPUT_YUV656E (Missing)\n");
return -EINVAL;
- break;
case KS_OUTPUT_EXV:
- dprintk("ks0127: command DECODER_SET_OUTPUT: "
- "OUTPUT_EXV\n");
- ks0127_and_or(ks, KS_OFMTA, 0xf0, 0x09);
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_OUTPUT: OUTPUT_EXV\n");
+ ks0127_and_or(c, KS_OFMTA, 0xf0, 0x09);
break;
}
break;
- case DECODER_SET_NORM: //sam This block mixes old and new norm names...
+ case DECODER_SET_NORM: /* sam This block mixes old and new norm names... */
/* Set to automatic SECAM/Fsc mode */
- ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+ ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
ks->norm = *iarg;
- switch(*iarg)
- {
+ switch (*iarg) {
/* this is untested !! */
/* It just detects PAL_N/NTSC_M (no special frequencies) */
/* And you have to set the standard a second time afterwards */
case VIDEO_MODE_AUTO:
- dprintk("ks0127: command DECODER_SET_NORM: AUTO\n");
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_NORM: AUTO\n");
/* The chip determines the format */
/* based on the current field rate */
- ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
- ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ ks0127_and_or(c, KS_CMDA, 0xfc, 0x00);
+ ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
/* This is wrong for PAL ! As I said, */
/* you need to set the standard once again !! */
ks->format_height = 240;
@@ -598,84 +589,86 @@ static int ks0127_command(struct i2c_client *client,
break;
case VIDEO_MODE_NTSC:
- dprintk("ks0127: command DECODER_SET_NORM: NTSC_M\n");
- ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_NORM: NTSC_M\n");
+ ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
ks->format_height = 240;
ks->format_width = 704;
break;
case KS_STD_NTSC_N:
- dprintk("ks0127: command KS0127_SET_STANDARD: "
- "NTSC_N (fixme)\n");
- ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+ v4l_dbg(1, debug, c,
+ "KS0127_SET_NORM: NTSC_N (fixme)\n");
+ ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
ks->format_height = 240;
ks->format_width = 704;
break;
case VIDEO_MODE_PAL:
- dprintk("ks0127: command DECODER_SET_NORM: PAL_N\n");
- ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_NORM: PAL_N\n");
+ ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
ks->format_height = 290;
ks->format_width = 704;
break;
case KS_STD_PAL_M:
- dprintk("ks0127: command KS0127_SET_STANDARD: "
- "PAL_M (fixme)\n");
- ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+ v4l_dbg(1, debug, c,
+ "KS0127_SET_NORM: PAL_M (fixme)\n");
+ ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
ks->format_height = 290;
ks->format_width = 704;
break;
case VIDEO_MODE_SECAM:
- dprintk("ks0127: command KS0127_SET_STANDARD: "
- "SECAM\n");
+ v4l_dbg(1, debug, c,
+ "KS0127_SET_NORM: SECAM\n");
ks->format_height = 290;
ks->format_width = 704;
/* set to secam autodetection */
- ks0127_and_or(ks, KS_CHROMA, 0xdf, 0x20);
- ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+ ks0127_and_or(c, KS_CHROMA, 0xdf, 0x20);
+ ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
schedule_timeout_interruptible(HZ/10+1);
/* did it autodetect? */
- if (ks0127_read(ks, KS_DEMOD) & 0x40)
+ if (ks0127_read(c, KS_DEMOD) & 0x40)
break;
/* force to secam mode */
- ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x0f);
+ ks0127_and_or(c, KS_DEMOD, 0xf0, 0x0f);
break;
default:
- dprintk("ks0127: command DECODER_SET_NORM: "
- "Unknown norm %d\n", *iarg);
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_NORM: Unknown norm %d\n", *iarg);
break;
}
break;
case DECODER_SET_PICTURE:
- dprintk("ks0127: command DECODER_SET_PICTURE "
- "not yet supported (fixme)\n");
+ v4l_dbg(1, debug, c,
+ "DECODER_SET_PICTURE: not yet supported\n");
return -EINVAL;
- //sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE
- //sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE
- //sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE?
- //sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE
- //sam todo: KS0127_SET_AGC_MODE:
- //sam todo: KS0127_SET_AGC:
- //sam todo: KS0127_SET_CHROMA_MODE:
- //sam todo: KS0127_SET_PIXCLK_MODE:
- //sam todo: KS0127_SET_GAMMA_MODE:
- //sam todo: KS0127_SET_UGAIN:
- //sam todo: KS0127_SET_VGAIN:
- //sam todo: KS0127_SET_INVALY:
- //sam todo: KS0127_SET_INVALU:
- //sam todo: KS0127_SET_INVALV:
- //sam todo: KS0127_SET_UNUSEY:
- //sam todo: KS0127_SET_UNUSEU:
- //sam todo: KS0127_SET_UNUSEV:
- //sam todo: KS0127_SET_VSALIGN_MODE:
+ /* sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE */
+ /* sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE */
+ /* sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE? */
+ /* sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE */
+ /* sam todo: KS0127_SET_AGC_MODE: */
+ /* sam todo: KS0127_SET_AGC: */
+ /* sam todo: KS0127_SET_CHROMA_MODE: */
+ /* sam todo: KS0127_SET_PIXCLK_MODE: */
+ /* sam todo: KS0127_SET_GAMMA_MODE: */
+ /* sam todo: KS0127_SET_UGAIN: */
+ /* sam todo: KS0127_SET_VGAIN: */
+ /* sam todo: KS0127_SET_INVALY: */
+ /* sam todo: KS0127_SET_INVALU: */
+ /* sam todo: KS0127_SET_INVALV: */
+ /* sam todo: KS0127_SET_UNUSEY: */
+ /* sam todo: KS0127_SET_UNUSEU: */
+ /* sam todo: KS0127_SET_UNUSEV: */
+ /* sam todo: KS0127_SET_VSALIGN_MODE: */
case DECODER_ENABLE_OUTPUT:
{
@@ -684,34 +677,32 @@ static int ks0127_command(struct i2c_client *client,
iarg = arg;
enable = (*iarg != 0);
if (enable) {
- dprintk("ks0127: command "
- "DECODER_ENABLE_OUTPUT on "
- "(%d)\n", enable);
+ v4l_dbg(1, debug, c,
+ "DECODER_ENABLE_OUTPUT on\n");
/* All output pins on */
- ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+ ks0127_and_or(c, KS_OFMTA, 0xcf, 0x30);
/* Obey the OEN pin */
- ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+ ks0127_and_or(c, KS_CDEM, 0x7f, 0x00);
} else {
- dprintk("ks0127: command "
- "DECODER_ENABLE_OUTPUT off "
- "(%d)\n", enable);
+ v4l_dbg(1, debug, c,
+ "DECODER_ENABLE_OUTPUT off\n");
/* Video output pins off */
- ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+ ks0127_and_or(c, KS_OFMTA, 0xcf, 0x00);
/* Ignore the OEN pin */
- ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+ ks0127_and_or(c, KS_CDEM, 0x7f, 0x80);
}
- }
break;
+ }
- //sam todo: KS0127_SET_OUTPUT_MODE:
- //sam todo: KS0127_SET_WIDTH:
- //sam todo: KS0127_SET_HEIGHT:
- //sam todo: KS0127_SET_HSCALE:
+ /* sam todo: KS0127_SET_OUTPUT_MODE: */
+ /* sam todo: KS0127_SET_WIDTH: */
+ /* sam todo: KS0127_SET_HEIGHT: */
+ /* sam todo: KS0127_SET_HSCALE: */
case DECODER_GET_STATUS:
- dprintk("ks0127: command DECODER_GET_STATUS\n");
+ v4l_dbg(1, debug, c, "DECODER_GET_STATUS\n");
*iarg = 0;
- status = ks0127_read(ks, KS_STAT);
+ status = ks0127_read(c, KS_STAT);
if (!(status & 0x20)) /* NOVID not set */
*iarg = (*iarg | DECODER_STATUS_GOOD);
if ((status & 0x01)) /* CLOCK set */
@@ -722,124 +713,81 @@ static int ks0127_command(struct i2c_client *client,
*iarg = (*iarg | DECODER_STATUS_NTSC);
break;
- //Catch any unknown command
+ /* Catch any unknown command */
default:
- dprintk("ks0127: command unknown: %04X\n", cmd);
+ v4l_dbg(1, debug, c, "unknown: 0x%08x\n", cmd);
return -EINVAL;
}
return 0;
}
-
-
-static int ks0127_probe(struct i2c_adapter *adapter);
-static int ks0127_detach(struct i2c_client *client);
-static int ks0127_command(struct i2c_client *client,
- unsigned int cmd, void *arg);
-
-
-
/* Addresses to scan */
-static unsigned short normal_i2c[] = {I2C_KS0127_ADDON>>1,
- I2C_KS0127_ONBOARD>>1, I2C_CLIENT_END};
-static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
-static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
-static struct i2c_client_address_data addr_data = {
- normal_i2c,
- probe,
- ignore,
-};
+#define I2C_KS0127_ADDON 0xD8
+#define I2C_KS0127_ONBOARD 0xDA
-static struct i2c_driver i2c_driver_ks0127 = {
- .driver.name = "ks0127",
- .id = I2C_DRIVERID_KS0127,
- .attach_adapter = ks0127_probe,
- .detach_client = ks0127_detach,
- .command = ks0127_command
+static unsigned short normal_i2c[] = {
+ I2C_KS0127_ADDON >> 1,
+ I2C_KS0127_ONBOARD >> 1,
+ I2C_CLIENT_END
};
-static struct i2c_client ks0127_client_tmpl =
-{
- .name = "(ks0127 unset)",
- .addr = 0,
- .adapter = NULL,
- .driver = &i2c_driver_ks0127,
-};
+I2C_CLIENT_INSMOD;
-static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
+static int ks0127_probe(struct i2c_client *c, const struct i2c_device_id *id)
{
struct ks0127 *ks;
- struct i2c_client *client;
- client = kzalloc(sizeof(*client), GFP_KERNEL);
- if (client == NULL)
- return -ENOMEM;
- memcpy(client, &ks0127_client_tmpl, sizeof(*client));
+ v4l_info(c, "%s chip found @ 0x%x (%s)\n",
+ c->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
+ c->addr << 1, c->adapter->name);
ks = kzalloc(sizeof(*ks), GFP_KERNEL);
- if (ks == NULL) {
- kfree(client);
+ if (ks == NULL)
return -ENOMEM;
- }
- i2c_set_clientdata(client, ks);
- client->adapter = adapter;
- client->addr = addr;
- sprintf(client->name, "ks0127-%02x", adapter->id);
+ i2c_set_clientdata(c, ks);
- ks->client = client;
- ks->addr = addr;
ks->ks_type = KS_TYPE_UNKNOWN;
/* power up */
- ks0127_write(ks, KS_CMDA, 0x2c);
+ init_reg_defaults();
+ ks0127_write(c, KS_CMDA, 0x2c);
mdelay(10);
/* reset the device */
- ks0127_reset(ks);
- printk(KERN_INFO "ks0127: attach: %s video decoder\n",
- ks->addr==(I2C_KS0127_ADDON>>1) ? "addon" : "on-board");
-
- i2c_attach_client(client);
+ ks0127_reset(c);
return 0;
}
-
-static int ks0127_probe(struct i2c_adapter *adapter)
+static int ks0127_remove(struct i2c_client *c)
{
- if (adapter->id == I2C_HW_B_ZR36067)
- return i2c_probe(adapter, &addr_data, ks0127_found_proc);
- return 0;
-}
-
-static int ks0127_detach(struct i2c_client *client)
-{
- struct ks0127 *ks = i2c_get_clientdata(client);
+ struct ks0127 *ks = i2c_get_clientdata(c);
- ks0127_write(ks, KS_OFMTA, 0x20); /*tristate*/
- ks0127_write(ks, KS_CMDA, 0x2c | 0x80); /* power down */
+ ks0127_write(c, KS_OFMTA, 0x20); /* tristate */
+ ks0127_write(c, KS_CMDA, 0x2c | 0x80); /* power down */
- i2c_detach_client(client);
kfree(ks);
- kfree(client);
-
- dprintk("ks0127: detach\n");
return 0;
}
-
-static int __devinit ks0127_init_module(void)
+static int ks0127_legacy_probe(struct i2c_adapter *adapter)
{
- init_reg_defaults();
- return i2c_add_driver(&i2c_driver_ks0127);
+ return adapter->id == I2C_HW_B_ZR36067;
}
-static void __devexit ks0127_cleanup_module(void)
-{
- i2c_del_driver(&i2c_driver_ks0127);
-}
-
-
-module_init(ks0127_init_module);
-module_exit(ks0127_cleanup_module);
+static const struct i2c_device_id ks0127_id[] = {
+ { "ks0127", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ks0127_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "ks0127",
+ .driverid = I2C_DRIVERID_KS0127,
+ .command = ks0127_command,
+ .probe = ks0127_probe,
+ .remove = ks0127_remove,
+ .legacy_probe = ks0127_legacy_probe,
+ .id_table = ks0127_id,
+};
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index 935d73de57b..210f1240b33 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -1098,9 +1098,10 @@ ov51x_clear_snapshot(struct usb_ov511 *ov)
reg_w(ov, R51x_SYS_SNAP, 0x02);
reg_w(ov, R51x_SYS_SNAP, 0x00);
} else if (ov->bclass == BCL_OV518) {
- warn("snapshot reset not supported yet on OV518(+)");
+ dev_warn(&ov->dev->dev,
+ "snapshot reset not supported yet on OV518(+)\n");
} else {
- err("clear snap: invalid bridge type");
+ dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
}
}
@@ -1115,14 +1116,16 @@ ov51x_check_snapshot(struct usb_ov511 *ov)
if (ov->bclass == BCL_OV511) {
ret = reg_r(ov, R51x_SYS_SNAP);
if (ret < 0) {
- err("Error checking snspshot status (%d)", ret);
+ dev_err(&ov->dev->dev,
+ "Error checking snspshot status (%d)\n", ret);
} else if (ret & 0x08) {
status = 1;
}
} else if (ov->bclass == BCL_OV518) {
- warn("snapshot check not supported yet on OV518(+)");
+ dev_warn(&ov->dev->dev,
+ "snapshot check not supported yet on OV518(+)\n");
} else {
- err("check snap: invalid bridge type");
+ dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
}
return status;
@@ -5217,7 +5220,8 @@ saa7111a_configure(struct usb_ov511 *ov)
if (ov->bclass == BCL_OV511)
reg_w(ov, 0x11, 0x00);
else
- warn("SAA7111A not yet supported with OV518/OV518+");
+ dev_warn(&ov->dev->dev,
+ "SAA7111A not yet supported with OV518/OV518+\n");
return 0;
}
@@ -5456,7 +5460,8 @@ ov518_configure(struct usb_ov511 *ov)
* required. OV518 has no uncompressed mode, to save RAM. */
if (!dumppix && !ov->compress) {
ov->compress = 1;
- warn("Compression required with OV518...enabling");
+ dev_warn(&ov->dev->dev,
+ "Compression required with OV518...enabling\n");
}
if (ov->bridge == BRG_OV518) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index a1252d673b4..273d2a1aa22 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -402,6 +402,10 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
+ /* prevent the PTSs from slowly drifting away in the generated
+ MPEG stream */
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC, 2, 4, 1);
+
return ret;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 94265bd3d92..5b81ba46964 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -60,7 +60,6 @@ static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
static DEFINE_MUTEX(pvr2_unit_mtx);
static int ctlchg;
-static int initusbreset = 1;
static int procreload;
static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
@@ -71,8 +70,6 @@ module_param(ctlchg, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");
module_param(init_pause_msec, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay");
-module_param(initusbreset, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe");
module_param(procreload, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(procreload,
"Attempt init failure recovery with firmware reload");
@@ -1967,9 +1964,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
}
hdw->fw1_state = FW1_STATE_OK;
- if (initusbreset) {
- pvr2_hdw_device_reset(hdw);
- }
if (!pvr2_hdw_dev_ok(hdw)) return;
for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index f048d80b77e..97ed9595799 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -168,7 +168,7 @@ static const char *get_v4l_name(int v4l_type)
* This is part of Video 4 Linux API. The procedure handles ioctl() calls.
*
*/
-static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
+static int __pvr2_v4l2_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
struct pvr2_v4l2_fh *fh = file->private_data;
@@ -863,8 +863,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
#endif
default :
- ret = v4l_compat_translate_ioctl(inode,file,cmd,
- arg,pvr2_v4l2_do_ioctl);
+ ret = v4l_compat_translate_ioctl(file, cmd,
+ arg, __pvr2_v4l2_do_ioctl);
}
pvr2_hdw_commit_ctl(hdw);
@@ -890,10 +890,15 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
return ret;
}
+static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ return __pvr2_v4l2_do_ioctl(file, cmd, arg);
+}
static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
{
- int minor_id = dip->devbase.minor;
+ int num = dip->devbase.num;
struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
enum pvr2_config cfg = dip->config;
int v4l_type = dip->v4l_type;
@@ -909,7 +914,7 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
video_unregister_device(&dip->devbase);
printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n",
- get_v4l_name(v4l_type),minor_id & 0x1f,
+ get_v4l_name(v4l_type), num,
pvr2_config_get_name(cfg));
}
@@ -1310,7 +1315,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
}
printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",
- get_v4l_name(dip->v4l_type),dip->devbase.minor & 0x1f,
+ get_v4l_name(dip->v4l_type), dip->devbase.num,
pvr2_config_get_name(dip->config));
pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index ab28389b4cd..f3897a3fdb7 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1795,7 +1795,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
goto err;
}
else {
- PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+ PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
}
/* occupy slot */
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 4aa82b31070..adf2ba79496 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -31,36 +31,24 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/wait.h>
-#include <asm/io.h>
#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
MODULE_AUTHOR("Pauline Middelink");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
-
-#define I2C_NAME(s) (s)->name
-
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <linux/video_decoder.h>
-
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
#define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */
#define SAA7110_MAX_OUTPUT 0 /* its a decoder only */
-#define I2C_SAA7110 0x9C /* or 0x9E */
-
#define SAA7110_NR_REG 0x35
struct saa7110 {
@@ -81,10 +69,7 @@ struct saa7110 {
/* I2C support functions */
/* ----------------------------------------------------------------------- */
-static int
-saa7110_write (struct i2c_client *client,
- u8 reg,
- u8 value)
+static int saa7110_write(struct i2c_client *client, u8 reg, u8 value)
{
struct saa7110 *decoder = i2c_get_clientdata(client);
@@ -92,10 +77,7 @@ saa7110_write (struct i2c_client *client,
return i2c_smbus_write_byte_data(client, reg, value);
}
-static int
-saa7110_write_block (struct i2c_client *client,
- const u8 *data,
- unsigned int len)
+static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
{
int ret = -1;
u8 reg = *data; /* first register to write to */
@@ -115,8 +97,8 @@ saa7110_write_block (struct i2c_client *client,
memcpy(decoder->reg + reg, data + 1, len - 1);
} else {
for (++data, --len; len; len--) {
- if ((ret = saa7110_write(client, reg++,
- *data++)) < 0)
+ ret = saa7110_write(client, reg++, *data++);
+ if (ret < 0)
break;
}
}
@@ -124,8 +106,7 @@ saa7110_write_block (struct i2c_client *client,
return ret;
}
-static inline int
-saa7110_read (struct i2c_client *client)
+static inline int saa7110_read(struct i2c_client *client)
{
return i2c_smbus_read_byte(client);
}
@@ -138,9 +119,7 @@ saa7110_read (struct i2c_client *client)
#define FRESP_06H_SVIDEO 0x83 //0xC0
-static int
-saa7110_selmux (struct i2c_client *client,
- int chan)
+static int saa7110_selmux(struct i2c_client *client, int chan)
{
static const unsigned char modes[9][8] = {
/* mode 0 */
@@ -197,8 +176,7 @@ static const unsigned char initseq[1 + SAA7110_NR_REG] = {
/* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
};
-static int
-determine_norm (struct i2c_client *client)
+static int determine_norm(struct i2c_client *client)
{
DEFINE_WAIT(wait);
struct saa7110 *decoder = i2c_get_clientdata(client);
@@ -212,29 +190,23 @@ determine_norm (struct i2c_client *client)
finish_wait(&decoder->wq, &wait);
status = saa7110_read(client);
if (status & 0x40) {
- dprintk(1, KERN_INFO "%s: status=0x%02x (no signal)\n",
- I2C_NAME(client), status);
+ v4l_dbg(1, debug, client, "status=0x%02x (no signal)\n", status);
return decoder->norm; // no change
}
if ((status & 3) == 0) {
saa7110_write(client, 0x06, 0x83);
if (status & 0x20) {
- dprintk(1,
- KERN_INFO
- "%s: status=0x%02x (NTSC/no color)\n",
- I2C_NAME(client), status);
+ v4l_dbg(1, debug, client, "status=0x%02x (NTSC/no color)\n", status);
//saa7110_write(client,0x2E,0x81);
return VIDEO_MODE_NTSC;
}
- dprintk(1, KERN_INFO "%s: status=0x%02x (PAL/no color)\n",
- I2C_NAME(client), status);
+ v4l_dbg(1, debug, client, "status=0x%02x (PAL/no color)\n", status);
//saa7110_write(client,0x2E,0x9A);
return VIDEO_MODE_PAL;
}
//saa7110_write(client,0x06,0x03);
if (status & 0x20) { /* 60Hz */
- dprintk(1, KERN_INFO "%s: status=0x%02x (NTSC)\n",
- I2C_NAME(client), status);
+ v4l_dbg(1, debug, client, "status=0x%02x (NTSC)\n", status);
saa7110_write(client, 0x0D, 0x86);
saa7110_write(client, 0x0F, 0x50);
saa7110_write(client, 0x11, 0x2C);
@@ -254,13 +226,11 @@ determine_norm (struct i2c_client *client)
status = saa7110_read(client);
if ((status & 0x03) == 0x01) {
- dprintk(1, KERN_INFO "%s: status=0x%02x (SECAM)\n",
- I2C_NAME(client), status);
+ v4l_dbg(1, debug, client, "status=0x%02x (SECAM)\n", status);
saa7110_write(client, 0x0D, 0x87);
return VIDEO_MODE_SECAM;
}
- dprintk(1, KERN_INFO "%s: status=0x%02x (PAL)\n", I2C_NAME(client),
- status);
+ v4l_dbg(1, debug, client, "status=0x%02x (PAL)\n", status);
return VIDEO_MODE_PAL;
}
@@ -286,8 +256,8 @@ saa7110_command (struct i2c_client *client,
VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
dc->inputs = SAA7110_MAX_INPUT;
dc->outputs = SAA7110_MAX_OUTPUT;
- }
break;
+ }
case DECODER_GET_STATUS:
{
@@ -295,8 +265,8 @@ saa7110_command (struct i2c_client *client,
int res = 0;
status = saa7110_read(client);
- dprintk(1, KERN_INFO "%s: status=0x%02x norm=%d\n",
- I2C_NAME(client), status, decoder->norm);
+ v4l_dbg(1, debug, client, "status=0x%02x norm=%d\n",
+ status, decoder->norm);
if (!(status & 0x40))
res |= DECODER_STATUS_GOOD;
if (status & 0x03)
@@ -314,8 +284,8 @@ saa7110_command (struct i2c_client *client,
break;
}
*(int *) arg = res;
- }
break;
+ }
case DECODER_SET_NORM:
v = *(int *) arg;
@@ -328,34 +298,24 @@ saa7110_command (struct i2c_client *client,
saa7110_write(client, 0x0F, 0x50);
saa7110_write(client, 0x11, 0x2C);
//saa7110_write(client, 0x2E, 0x81);
- dprintk(1,
- KERN_INFO "%s: switched to NTSC\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "switched to NTSC\n");
break;
case VIDEO_MODE_PAL:
saa7110_write(client, 0x0D, 0x86);
saa7110_write(client, 0x0F, 0x10);
saa7110_write(client, 0x11, 0x59);
//saa7110_write(client, 0x2E, 0x9A);
- dprintk(1,
- KERN_INFO "%s: switched to PAL\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "switched to PAL\n");
break;
case VIDEO_MODE_SECAM:
saa7110_write(client, 0x0D, 0x87);
saa7110_write(client, 0x0F, 0x10);
saa7110_write(client, 0x11, 0x59);
//saa7110_write(client, 0x2E, 0x9A);
- dprintk(1,
- KERN_INFO
- "%s: switched to SECAM\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "switched to SECAM\n");
break;
case VIDEO_MODE_AUTO:
- dprintk(1,
- KERN_INFO
- "%s: TV standard detection...\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "switched to AUTO\n");
decoder->norm = determine_norm(client);
*(int *) arg = decoder->norm;
break;
@@ -368,15 +328,12 @@ saa7110_command (struct i2c_client *client,
case DECODER_SET_INPUT:
v = *(int *) arg;
if (v < 0 || v > SAA7110_MAX_INPUT) {
- dprintk(1,
- KERN_INFO "%s: input=%d not available\n",
- I2C_NAME(client), v);
+ v4l_dbg(1, debug, client, "input=%d not available\n", v);
return -EINVAL;
}
if (decoder->input != v) {
saa7110_selmux(client, v);
- dprintk(1, KERN_INFO "%s: switched to input=%d\n",
- I2C_NAME(client), v);
+ v4l_dbg(1, debug, client, "switched to input=%d\n", v);
}
break;
@@ -392,8 +349,7 @@ saa7110_command (struct i2c_client *client,
if (decoder->enable != v) {
decoder->enable = v;
saa7110_write(client, 0x0E, v ? 0x18 : 0x80);
- dprintk(1, KERN_INFO "%s: YUV %s\n", I2C_NAME(client),
- v ? "on" : "off");
+ v4l_dbg(1, debug, client, "YUV %s\n", v ? "on" : "off");
}
break;
@@ -423,23 +379,23 @@ saa7110_command (struct i2c_client *client,
saa7110_write(client, 0x07,
(decoder->hue >> 8) - 128);
}
- }
break;
+ }
case DECODER_DUMP:
+ if (!debug)
+ break;
for (v = 0; v < SAA7110_NR_REG; v += 16) {
int j;
- dprintk(1, KERN_DEBUG "%s: %02x:", I2C_NAME(client),
- v);
+ v4l_dbg(1, debug, client, "%02x:", v);
for (j = 0; j < 16 && v + j < SAA7110_NR_REG; j++)
- dprintk(1, " %02x", decoder->reg[v + j]);
- dprintk(1, "\n");
+ printk(KERN_CONT " %02x", decoder->reg[v + j]);
+ printk(KERN_CONT "\n");
}
break;
default:
- dprintk(1, KERN_INFO "unknown saa7110_command??(%d)\n",
- cmd);
+ v4l_dbg(1, debug, client, "unknown command %08x\n", cmd);
return -EINVAL;
}
return 0;
@@ -451,55 +407,28 @@ saa7110_command (struct i2c_client *client,
* Generic i2c probe
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static unsigned short normal_i2c[] = {
- I2C_SAA7110 >> 1,
- (I2C_SAA7110 >> 1) + 1,
- 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 unsigned short normal_i2c[] = { 0x9c >> 1, 0x9e >> 1, I2C_CLIENT_END };
-static struct i2c_driver i2c_driver_saa7110;
+I2C_CLIENT_INSMOD;
-static int
-saa7110_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
+static int saa7110_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct i2c_client *client;
struct saa7110 *decoder;
int rv;
- dprintk(1,
- KERN_INFO
- "saa7110.c: detecting saa7110 client on address 0x%x\n",
- address << 1);
-
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality
- (adapter,
- I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
- return 0;
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ return -ENODEV;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_saa7110;
- strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client)));
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
- if (!decoder) {
- kfree(client);
+ if (!decoder)
return -ENOMEM;
- }
decoder->norm = VIDEO_MODE_PAL;
decoder->input = 0;
decoder->enable = 1;
@@ -510,18 +439,10 @@ saa7110_detect_client (struct i2c_adapter *adapter,
init_waitqueue_head(&decoder->wq);
i2c_set_clientdata(client, decoder);
- rv = i2c_attach_client(client);
- if (rv) {
- kfree(client);
- kfree(decoder);
- return rv;
- }
-
rv = saa7110_write_block(client, initseq, sizeof(initseq));
- if (rv < 0)
- dprintk(1, KERN_ERR "%s_attach: init status %d\n",
- I2C_NAME(client), rv);
- else {
+ if (rv < 0) {
+ v4l_dbg(1, debug, client, "init status %d\n", rv);
+ } else {
int ver, status;
saa7110_write(client, 0x21, 0x10);
saa7110_write(client, 0x0e, 0x18);
@@ -530,10 +451,8 @@ saa7110_detect_client (struct i2c_adapter *adapter,
saa7110_write(client, 0x0D, 0x06);
//mdelay(150);
status = saa7110_read(client);
- dprintk(1,
- KERN_INFO
- "%s_attach: SAA7110A version %x at 0x%02x, status=0x%02x\n",
- I2C_NAME(client), ver, client->addr << 1, status);
+ v4l_dbg(1, debug, client, "version %x, status=0x%02x\n",
+ ver, status);
saa7110_write(client, 0x0D, 0x86);
saa7110_write(client, 0x0F, 0x10);
saa7110_write(client, 0x11, 0x59);
@@ -547,58 +466,25 @@ saa7110_detect_client (struct i2c_adapter *adapter,
return 0;
}
-static int
-saa7110_attach_adapter (struct i2c_adapter *adapter)
-{
- dprintk(1,
- KERN_INFO
- "saa7110.c: starting probe for adapter %s (0x%x)\n",
- I2C_NAME(adapter), adapter->id);
- return i2c_probe(adapter, &addr_data, &saa7110_detect_client);
-}
-
-static int
-saa7110_detach_client (struct i2c_client *client)
+static int saa7110_remove(struct i2c_client *client)
{
- struct saa7110 *decoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
-
- kfree(decoder);
- kfree(client);
-
+ kfree(i2c_get_clientdata(client));
return 0;
}
/* ----------------------------------------------------------------------- */
-static struct i2c_driver i2c_driver_saa7110 = {
- .driver = {
- .name = "saa7110",
- },
-
- .id = I2C_DRIVERID_SAA7110,
+static const struct i2c_device_id saa7110_id[] = {
+ { "saa7110", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7110_id);
- .attach_adapter = saa7110_attach_adapter,
- .detach_client = saa7110_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa7110",
+ .driverid = I2C_DRIVERID_SAA7110,
.command = saa7110_command,
+ .probe = saa7110_probe,
+ .remove = saa7110_remove,
+ .id_table = saa7110_id,
};
-
-static int __init
-saa7110_init (void)
-{
- return i2c_add_driver(&i2c_driver_saa7110);
-}
-
-static void __exit
-saa7110_exit (void)
-{
- i2c_del_driver(&i2c_driver_saa7110);
-}
-
-module_init(saa7110_init);
-module_exit(saa7110_exit);
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index 96c3d435772..a4738a2fb4d 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -28,43 +28,24 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
#include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
#include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/videodev.h>
#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-
-#define I2C_NAME(s) (s)->name
-
-
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
/* ----------------------------------------------------------------------- */
#define SAA7111_NR_REG 0x18
@@ -77,14 +58,9 @@ struct saa7111 {
int enable;
};
-#define I2C_SAA7111 0x48
-
/* ----------------------------------------------------------------------- */
-static inline int
-saa7111_write (struct i2c_client *client,
- u8 reg,
- u8 value)
+static inline int saa7111_write(struct i2c_client *client, u8 reg, u8 value)
{
struct saa7111 *decoder = i2c_get_clientdata(client);
@@ -92,8 +68,7 @@ saa7111_write (struct i2c_client *client,
return i2c_smbus_write_byte_data(client, reg, value);
}
-static inline void
-saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
+static inline void saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
{
struct saa7111 *decoder = i2c_get_clientdata(client);
@@ -103,10 +78,7 @@ saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
}
}
-static int
-saa7111_write_block (struct i2c_client *client,
- const u8 *data,
- unsigned int len)
+static int saa7111_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
{
int ret = -1;
u8 reg;
@@ -127,18 +99,17 @@ saa7111_write_block (struct i2c_client *client,
decoder->reg[reg++] = data[1];
len -= 2;
data += 2;
- } while (len >= 2 && data[0] == reg &&
- block_len < 32);
- if ((ret = i2c_master_send(client, block_data,
- block_len)) < 0)
+ } while (len >= 2 && data[0] == reg && block_len < 32);
+ ret = i2c_master_send(client, block_data, block_len);
+ if (ret < 0)
break;
}
} else {
/* do some slow I2C emulation kind of thing */
while (len >= 2) {
reg = *data++;
- if ((ret = saa7111_write(client, reg,
- *data++)) < 0)
+ ret = saa7111_write(client, reg, *data++);
+ if (ret < 0)
break;
len -= 2;
}
@@ -147,16 +118,13 @@ saa7111_write_block (struct i2c_client *client,
return ret;
}
-static int
-saa7111_init_decoder (struct i2c_client *client,
- struct video_decoder_init *init)
+static int saa7111_init_decoder(struct i2c_client *client,
+ struct video_decoder_init *init)
{
return saa7111_write_block(client, init->data, init->len);
}
-static inline int
-saa7111_read (struct i2c_client *client,
- u8 reg)
+static inline int saa7111_read(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
@@ -203,28 +171,23 @@ static const unsigned char saa7111_i2c_init[] = {
0x17, 0x00, /* 17 - VBI */
};
-static int
-saa7111_command (struct i2c_client *client,
- unsigned int cmd,
- void *arg)
+static int saa7111_command(struct i2c_client *client, unsigned cmd, void *arg)
{
struct saa7111 *decoder = i2c_get_clientdata(client);
switch (cmd) {
-
case 0:
break;
case DECODER_INIT:
{
struct video_decoder_init *init = arg;
+ struct video_decoder_init vdi;
+
if (NULL != init)
return saa7111_init_decoder(client, init);
- else {
- struct video_decoder_init vdi;
- vdi.data = saa7111_i2c_init;
- vdi.len = sizeof(saa7111_i2c_init);
- return saa7111_init_decoder(client, &vdi);
- }
+ vdi.data = saa7111_i2c_init;
+ vdi.len = sizeof(saa7111_i2c_init);
+ return saa7111_init_decoder(client, &vdi);
}
case DECODER_DUMP:
@@ -234,15 +197,15 @@ saa7111_command (struct i2c_client *client,
for (i = 0; i < SAA7111_NR_REG; i += 16) {
int j;
- printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+ v4l_info(client, "%03x", i);
for (j = 0; j < 16 && i + j < SAA7111_NR_REG; ++j) {
- printk(" %02x",
+ printk(KERN_CONT " %02x",
saa7111_read(client, i + j));
}
- printk("\n");
+ printk(KERN_CONT "\n");
}
- }
break;
+ }
case DECODER_GET_CAPABILITIES:
{
@@ -255,8 +218,8 @@ saa7111_command (struct i2c_client *client,
VIDEO_DECODER_CCIR;
cap->inputs = 8;
cap->outputs = 1;
- }
break;
+ }
case DECODER_GET_STATUS:
{
@@ -265,8 +228,7 @@ saa7111_command (struct i2c_client *client,
int res;
status = saa7111_read(client, 0x1f);
- dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
- status);
+ v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
res = 0;
if ((status & (1 << 6)) == 0) {
res |= DECODER_STATUS_GOOD;
@@ -294,8 +256,8 @@ saa7111_command (struct i2c_client *client,
res |= DECODER_STATUS_COLOR;
}
*iarg = res;
- }
break;
+ }
case DECODER_SET_GPIO:
{
@@ -362,8 +324,8 @@ saa7111_command (struct i2c_client *client,
}
decoder->norm = *iarg;
- }
break;
+ }
case DECODER_SET_INPUT:
{
@@ -387,8 +349,8 @@ saa7111_command (struct i2c_client *client,
3) ? 0x80 :
0));
}
- }
break;
+ }
case DECODER_SET_OUTPUT:
{
@@ -398,8 +360,8 @@ saa7111_command (struct i2c_client *client,
if (*iarg != 0) {
return -EINVAL;
}
- }
break;
+ }
case DECODER_ENABLE_OUTPUT:
{
@@ -439,8 +401,8 @@ saa7111_command (struct i2c_client *client,
(decoder->reg[0x11] & 0xf3));
}
}
- }
break;
+ }
case DECODER_SET_PICTURE:
{
@@ -454,8 +416,8 @@ saa7111_command (struct i2c_client *client,
saa7111_write(client, 0x0c, pic->colour >> 9);
/* We want -128 to 127 we get 0-65535 */
saa7111_write(client, 0x0d, (pic->hue - 32768) >> 8);
- }
break;
+ }
default:
return -EINVAL;
@@ -466,48 +428,23 @@ saa7111_command (struct i2c_client *client,
/* ----------------------------------------------------------------------- */
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, 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 unsigned short normal_i2c[] = { 0x48 >> 1, I2C_CLIENT_END };
-static struct i2c_driver i2c_driver_saa7111;
+I2C_CLIENT_INSMOD;
-static int
-saa7111_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
+static int saa7111_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int i;
- struct i2c_client *client;
struct saa7111 *decoder;
struct video_decoder_init vdi;
- dprintk(1,
- KERN_INFO
- "saa7111.c: detecting saa7111 client on address 0x%x\n",
- address << 1);
-
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return 0;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_saa7111;
- strlcpy(I2C_NAME(client), "saa7111", sizeof(I2C_NAME(client)));
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
decoder = kzalloc(sizeof(struct saa7111), GFP_KERNEL);
if (decoder == NULL) {
@@ -519,82 +456,37 @@ saa7111_detect_client (struct i2c_adapter *adapter,
decoder->enable = 1;
i2c_set_clientdata(client, decoder);
- i = i2c_attach_client(client);
- if (i) {
- kfree(client);
- kfree(decoder);
- return i;
- }
-
vdi.data = saa7111_i2c_init;
vdi.len = sizeof(saa7111_i2c_init);
i = saa7111_init_decoder(client, &vdi);
if (i < 0) {
- dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
- I2C_NAME(client), i);
+ v4l_dbg(1, debug, client, "init status %d\n", i);
} else {
- dprintk(1,
- KERN_INFO
- "%s_attach: chip version %x at address 0x%x\n",
- I2C_NAME(client), saa7111_read(client, 0x00) >> 4,
- client->addr << 1);
+ v4l_dbg(1, debug, client, "revision %x\n",
+ saa7111_read(client, 0x00) >> 4);
}
-
return 0;
}
-static int
-saa7111_attach_adapter (struct i2c_adapter *adapter)
+static int saa7111_remove(struct i2c_client *client)
{
- dprintk(1,
- KERN_INFO
- "saa7111.c: starting probe for adapter %s (0x%x)\n",
- I2C_NAME(adapter), adapter->id);
- return i2c_probe(adapter, &addr_data, &saa7111_detect_client);
-}
-
-static int
-saa7111_detach_client (struct i2c_client *client)
-{
- struct saa7111 *decoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
-
- kfree(decoder);
- kfree(client);
-
+ kfree(i2c_get_clientdata(client));
return 0;
}
/* ----------------------------------------------------------------------- */
-static struct i2c_driver i2c_driver_saa7111 = {
- .driver = {
- .name = "saa7111",
- },
-
- .id = I2C_DRIVERID_SAA7111A,
+static const struct i2c_device_id saa7111_id[] = {
+ { "saa7111_old", 0 }, /* "saa7111" maps to the saa7115 driver */
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7111_id);
- .attach_adapter = saa7111_attach_adapter,
- .detach_client = saa7111_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa7111",
+ .driverid = I2C_DRIVERID_SAA7111A,
.command = saa7111_command,
+ .probe = saa7111_probe,
+ .remove = saa7111_remove,
+ .id_table = saa7111_id,
};
-
-static int __init
-saa7111_init (void)
-{
- return i2c_add_driver(&i2c_driver_saa7111);
-}
-
-static void __exit
-saa7111_exit (void)
-{
- i2c_del_driver(&i2c_driver_saa7111);
-}
-
-module_init(saa7111_init);
-module_exit(saa7111_exit);
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index e79075533be..7ca709fda5f 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -29,43 +29,24 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
#include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
#include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/videodev.h>
#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
MODULE_LICENSE("GPL");
-
-#define I2C_NAME(x) (x)->name
-
-
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
/* ----------------------------------------------------------------------- */
struct saa7114 {
@@ -81,9 +62,6 @@ struct saa7114 {
int playback;
};
-#define I2C_SAA7114 0x42
-#define I2C_SAA7114A 0x40
-
#define I2C_DELAY 10
@@ -129,18 +107,12 @@ struct saa7114 {
/* ----------------------------------------------------------------------- */
-static inline int
-saa7114_write (struct i2c_client *client,
- u8 reg,
- u8 value)
+static inline int saa7114_write(struct i2c_client *client, u8 reg, u8 value)
{
return i2c_smbus_write_byte_data(client, reg, value);
}
-static int
-saa7114_write_block (struct i2c_client *client,
- const u8 *data,
- unsigned int len)
+static int saa7114_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
{
int ret = -1;
u8 reg;
@@ -160,18 +132,17 @@ saa7114_write_block (struct i2c_client *client,
reg++;
len -= 2;
data += 2;
- } while (len >= 2 && data[0] == reg &&
- block_len < 32);
- if ((ret = i2c_master_send(client, block_data,
- block_len)) < 0)
+ } while (len >= 2 && data[0] == reg && block_len < 32);
+ ret = i2c_master_send(client, block_data, block_len);
+ if (ret < 0)
break;
}
} else {
/* do some slow I2C emulation kind of thing */
while (len >= 2) {
reg = *data++;
- if ((ret = saa7114_write(client, reg,
- *data++)) < 0)
+ ret = saa7114_write(client, reg, *data++);
+ if (ret < 0)
break;
len -= 2;
}
@@ -180,9 +151,7 @@ saa7114_write_block (struct i2c_client *client,
return ret;
}
-static inline int
-saa7114_read (struct i2c_client *client,
- u8 reg)
+static inline int saa7114_read(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
@@ -452,15 +421,11 @@ static const unsigned char init[] = {
0xef, 0x00
};
-static int
-saa7114_command (struct i2c_client *client,
- unsigned int cmd,
- void *arg)
+static int saa7114_command(struct i2c_client *client, unsigned cmd, void *arg)
{
struct saa7114 *decoder = i2c_get_clientdata(client);
switch (cmd) {
-
case 0:
//dprintk(1, KERN_INFO "%s: writing init\n", I2C_NAME(client));
//saa7114_write_block(client, init, sizeof(init));
@@ -470,27 +435,28 @@ saa7114_command (struct i2c_client *client,
{
int i;
- dprintk(1, KERN_INFO "%s: decoder dump\n", I2C_NAME(client));
+ if (!debug)
+ break;
+ v4l_info(client, "decoder dump\n");
for (i = 0; i < 32; i += 16) {
int j;
- printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+ v4l_info(client, "%03x", i);
for (j = 0; j < 16; ++j) {
- printk(" %02x",
+ printk(KERN_CONT " %02x",
saa7114_read(client, i + j));
}
- printk("\n");
+ printk(KERN_CONT "\n");
}
- }
break;
+ }
case DECODER_GET_CAPABILITIES:
{
struct video_decoder_capability *cap = arg;
- dprintk(1, KERN_DEBUG "%s: decoder get capabilities\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "get capabilities\n");
cap->flags = VIDEO_DECODER_PAL |
VIDEO_DECODER_NTSC |
@@ -498,8 +464,8 @@ saa7114_command (struct i2c_client *client,
VIDEO_DECODER_CCIR;
cap->inputs = 8;
cap->outputs = 1;
- }
break;
+ }
case DECODER_GET_STATUS:
{
@@ -509,8 +475,7 @@ saa7114_command (struct i2c_client *client,
status = saa7114_read(client, 0x1f);
- dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
- status);
+ v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
res = 0;
if ((status & (1 << 6)) == 0) {
res |= DECODER_STATUS_GOOD;
@@ -538,8 +503,8 @@ saa7114_command (struct i2c_client *client,
res |= DECODER_STATUS_COLOR;
}
*iarg = res;
- }
break;
+ }
case DECODER_SET_NORM:
{
@@ -547,12 +512,11 @@ saa7114_command (struct i2c_client *client,
short int hoff = 0, voff = 0, w = 0, h = 0;
- dprintk(1, KERN_DEBUG "%s: decoder set norm ",
- I2C_NAME(client));
- switch (*iarg) {
+ v4l_dbg(1, debug, client, "set norm\n");
+ switch (*iarg) {
case VIDEO_MODE_NTSC:
- dprintk(1, "NTSC\n");
+ v4l_dbg(1, debug, client, "NTSC\n");
decoder->reg[REG_ADDR(0x06)] =
SAA_7114_NTSC_HSYNC_START;
decoder->reg[REG_ADDR(0x07)] =
@@ -571,7 +535,7 @@ saa7114_command (struct i2c_client *client,
break;
case VIDEO_MODE_PAL:
- dprintk(1, "PAL\n");
+ v4l_dbg(1, debug, client, "PAL\n");
decoder->reg[REG_ADDR(0x06)] =
SAA_7114_PAL_HSYNC_START;
decoder->reg[REG_ADDR(0x07)] =
@@ -590,9 +554,8 @@ saa7114_command (struct i2c_client *client,
break;
default:
- dprintk(1, " Unknown video mode!!!\n");
+ v4l_dbg(1, debug, client, "Unknown video mode\n");
return -EINVAL;
-
}
@@ -644,22 +607,20 @@ saa7114_command (struct i2c_client *client,
saa7114_write(client, 0x80, 0x36); // i-port and scaler back end clock selection
decoder->norm = *iarg;
- }
break;
+ }
case DECODER_SET_INPUT:
{
int *iarg = arg;
- dprintk(1, KERN_DEBUG "%s: decoder set input (%d)\n",
- I2C_NAME(client), *iarg);
+ v4l_dbg(1, debug, client, "set input (%d)\n", *iarg);
if (*iarg < 0 || *iarg > 7) {
return -EINVAL;
}
if (decoder->input != *iarg) {
- dprintk(1, KERN_DEBUG "%s: now setting %s input\n",
- I2C_NAME(client),
+ v4l_dbg(1, debug, client, "now setting %s input\n",
*iarg >= 6 ? "S-Video" : "Composite");
decoder->input = *iarg;
@@ -690,30 +651,29 @@ saa7114_command (struct i2c_client *client,
saa7114_write(client, 0x0e,
decoder->reg[REG_ADDR(0x0e)]);
}
- }
break;
+ }
case DECODER_SET_OUTPUT:
{
int *iarg = arg;
- dprintk(1, KERN_DEBUG "%s: decoder set output\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "set output\n");
/* not much choice of outputs */
if (*iarg != 0) {
return -EINVAL;
}
- }
break;
+ }
case DECODER_ENABLE_OUTPUT:
{
int *iarg = arg;
int enable = (*iarg != 0);
- dprintk(1, KERN_DEBUG "%s: decoder %s output\n",
- I2C_NAME(client), enable ? "enable" : "disable");
+ v4l_dbg(1, debug, client, "%s output\n",
+ enable ? "enable" : "disable");
decoder->playback = !enable;
@@ -754,18 +714,16 @@ saa7114_command (struct i2c_client *client,
saa7114_write(client, 0x80, 0x36);
}
- }
break;
+ }
case DECODER_SET_PICTURE:
{
struct video_picture *pic = arg;
- dprintk(1,
- KERN_DEBUG
- "%s: decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
- I2C_NAME(client), pic->brightness, pic->contrast,
- pic->colour, pic->hue);
+ v4l_dbg(1, debug, client,
+ "decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
+ pic->brightness, pic->contrast, pic->colour, pic->hue);
if (decoder->bright != pic->brightness) {
/* We want 0 to 255 we get 0-65535 */
@@ -789,8 +747,8 @@ saa7114_command (struct i2c_client *client,
saa7114_write(client, 0x0d,
(decoder->hue - 32768) >> 8);
}
- }
break;
+ }
default:
return -EINVAL;
@@ -801,58 +759,30 @@ saa7114_command (struct i2c_client *client,
/* ----------------------------------------------------------------------- */
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] =
- { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, 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 unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
-static struct i2c_driver i2c_driver_saa7114;
+I2C_CLIENT_INSMOD;
-static int
-saa7114_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
+static int saa7114_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int i, err[30];
short int hoff = SAA_7114_NTSC_HOFFSET;
short int voff = SAA_7114_NTSC_VOFFSET;
short int w = SAA_7114_NTSC_WIDTH;
short int h = SAA_7114_NTSC_HEIGHT;
- struct i2c_client *client;
struct saa7114 *decoder;
- dprintk(1,
- KERN_INFO
- "saa7114.c: detecting saa7114 client on address 0x%x\n",
- address << 1);
-
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return 0;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_saa7114;
- strlcpy(I2C_NAME(client), "saa7114", sizeof(I2C_NAME(client)));
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
decoder = kzalloc(sizeof(struct saa7114), GFP_KERNEL);
- if (decoder == NULL) {
- kfree(client);
+ if (decoder == NULL)
return -ENOMEM;
- }
decoder->norm = VIDEO_MODE_NTSC;
decoder->input = -1;
decoder->enable = 1;
@@ -937,8 +867,7 @@ saa7114_detect_client (struct i2c_adapter *adapter,
decoder->reg[REG_ADDR(0x0e)] |= 1; // combfilter on
- dprintk(1, KERN_DEBUG "%s_attach: starting decoder init\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "starting init\n");
err[0] =
saa7114_write_block(client, decoder->reg + (0x20 << 1),
@@ -962,28 +891,23 @@ saa7114_detect_client (struct i2c_adapter *adapter,
for (i = 0; i <= 5; i++) {
if (err[i] < 0) {
- dprintk(1,
- KERN_ERR
- "%s_attach: init error %d at stage %d, leaving attach.\n",
- I2C_NAME(client), i, err[i]);
+ v4l_dbg(1, debug, client,
+ "init error %d at stage %d, leaving attach.\n",
+ i, err[i]);
kfree(decoder);
- kfree(client);
- return 0;
+ return -EIO;
}
}
for (i = 6; i < 8; i++) {
- dprintk(1,
- KERN_DEBUG
- "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
- I2C_NAME(client), i, saa7114_read(client, i),
+ v4l_dbg(1, debug, client,
+ "reg[0x%02x] = 0x%02x (0x%02x)\n",
+ i, saa7114_read(client, i),
decoder->reg[REG_ADDR(i)]);
}
- dprintk(1,
- KERN_DEBUG
- "%s_attach: performing decoder reset sequence\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client,
+ "performing decoder reset sequence\n");
err[6] = saa7114_write(client, 0x80, 0x06); // i-port and scaler backend clock selection, task A&B off
err[7] = saa7114_write(client, 0x88, 0xd8); // sw reset scaler
@@ -991,19 +915,15 @@ saa7114_detect_client (struct i2c_adapter *adapter,
for (i = 6; i <= 8; i++) {
if (err[i] < 0) {
- dprintk(1,
- KERN_ERR
- "%s_attach: init error %d at stage %d, leaving attach.\n",
- I2C_NAME(client), i, err[i]);
+ v4l_dbg(1, debug, client,
+ "init error %d at stage %d, leaving attach.\n",
+ i, err[i]);
kfree(decoder);
- kfree(client);
- return 0;
+ return -EIO;
}
}
- dprintk(1, KERN_INFO "%s_attach: performing the rest of init\n",
- I2C_NAME(client));
-
+ v4l_dbg(1, debug, client, "performing the rest of init\n");
err[9] = saa7114_write(client, 0x01, decoder->reg[REG_ADDR(0x01)]);
err[10] = saa7114_write_block(client, decoder->reg + (0x03 << 1), (0x1e + 1 - 0x03) << 1); // big seq
@@ -1039,37 +959,32 @@ saa7114_detect_client (struct i2c_adapter *adapter,
for (i = 9; i <= 18; i++) {
if (err[i] < 0) {
- dprintk(1,
- KERN_ERR
- "%s_attach: init error %d at stage %d, leaving attach.\n",
- I2C_NAME(client), i, err[i]);
+ v4l_dbg(1, debug, client,
+ "init error %d at stage %d, leaving attach.\n",
+ i, err[i]);
kfree(decoder);
- kfree(client);
- return 0;
+ return -EIO;
}
}
for (i = 6; i < 8; i++) {
- dprintk(1,
- KERN_DEBUG
- "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
- I2C_NAME(client), i, saa7114_read(client, i),
+ v4l_dbg(1, debug, client,
+ "reg[0x%02x] = 0x%02x (0x%02x)\n",
+ i, saa7114_read(client, i),
decoder->reg[REG_ADDR(i)]);
}
for (i = 0x11; i <= 0x13; i++) {
- dprintk(1,
- KERN_DEBUG
- "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
- I2C_NAME(client), i, saa7114_read(client, i),
+ v4l_dbg(1, debug, client,
+ "reg[0x%02x] = 0x%02x (0x%02x)\n",
+ i, saa7114_read(client, i),
decoder->reg[REG_ADDR(i)]);
}
- dprintk(1, KERN_DEBUG "%s_attach: setting video input\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "setting video input\n");
err[19] =
saa7114_write(client, 0x02, decoder->reg[REG_ADDR(0x02)]);
@@ -1080,20 +995,15 @@ saa7114_detect_client (struct i2c_adapter *adapter,
for (i = 19; i <= 21; i++) {
if (err[i] < 0) {
- dprintk(1,
- KERN_ERR
- "%s_attach: init error %d at stage %d, leaving attach.\n",
- I2C_NAME(client), i, err[i]);
+ v4l_dbg(1, debug, client,
+ "init error %d at stage %d, leaving attach.\n",
+ i, err[i]);
kfree(decoder);
- kfree(client);
- return 0;
+ return -EIO;
}
}
- dprintk(1,
- KERN_DEBUG
- "%s_attach: performing decoder reset sequence\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "performing decoder reset sequence\n");
err[22] = saa7114_write(client, 0x88, 0xd8); // sw reset scaler
err[23] = saa7114_write(client, 0x88, 0xf8); // sw reset scaler release
@@ -1102,13 +1012,11 @@ saa7114_detect_client (struct i2c_adapter *adapter,
for (i = 22; i <= 24; i++) {
if (err[i] < 0) {
- dprintk(1,
- KERN_ERR
- "%s_attach: init error %d at stage %d, leaving attach.\n",
- I2C_NAME(client), i, err[i]);
+ v4l_dbg(1, debug, client,
+ "init error %d at stage %d, leaving attach.\n",
+ i, err[i]);
kfree(decoder);
- kfree(client);
- return 0;
+ return -EIO;
}
}
@@ -1116,101 +1024,45 @@ saa7114_detect_client (struct i2c_adapter *adapter,
err[26] = saa7114_write(client, 0x07, init[REG_ADDR(0x07)]);
err[27] = saa7114_write(client, 0x10, init[REG_ADDR(0x10)]);
- dprintk(1,
- KERN_INFO
- "%s_attach: chip version %x, decoder status 0x%02x\n",
- I2C_NAME(client), saa7114_read(client, 0x00) >> 4,
+ v4l_dbg(1, debug, client, "chip version %x, decoder status 0x%02x\n",
+ saa7114_read(client, 0x00) >> 4,
saa7114_read(client, 0x1f));
- dprintk(1,
- KERN_DEBUG
- "%s_attach: power save control: 0x%02x, scaler status: 0x%02x\n",
- I2C_NAME(client), saa7114_read(client, 0x88),
+ v4l_dbg(1, debug, client,
+ "power save control: 0x%02x, scaler status: 0x%02x\n",
+ saa7114_read(client, 0x88),
saa7114_read(client, 0x8f));
for (i = 0x94; i < 0x96; i++) {
- dprintk(1,
- KERN_DEBUG
- "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
- I2C_NAME(client), i, saa7114_read(client, i),
+ v4l_dbg(1, debug, client,
+ "reg[0x%02x] = 0x%02x (0x%02x)\n",
+ i, saa7114_read(client, i),
decoder->reg[REG_ADDR(i)]);
}
- i = i2c_attach_client(client);
- if (i) {
- kfree(client);
- kfree(decoder);
- return i;
- }
-
//i = saa7114_write_block(client, init, sizeof(init));
- i = 0;
- if (i < 0) {
- dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
- I2C_NAME(client), i);
- } else {
- dprintk(1,
- KERN_INFO
- "%s_attach: chip version %x at address 0x%x\n",
- I2C_NAME(client), saa7114_read(client, 0x00) >> 4,
- client->addr << 1);
- }
-
return 0;
}
-static int
-saa7114_attach_adapter (struct i2c_adapter *adapter)
-{
- dprintk(1,
- KERN_INFO
- "saa7114.c: starting probe for adapter %s (0x%x)\n",
- I2C_NAME(adapter), adapter->id);
- return i2c_probe(adapter, &addr_data, &saa7114_detect_client);
-}
-
-static int
-saa7114_detach_client (struct i2c_client *client)
+static int saa7114_remove(struct i2c_client *client)
{
- struct saa7114 *decoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
-
- kfree(decoder);
- kfree(client);
-
+ kfree(i2c_get_clientdata(client));
return 0;
}
/* ----------------------------------------------------------------------- */
-static struct i2c_driver i2c_driver_saa7114 = {
- .driver = {
- .name = "saa7114",
- },
-
- .id = I2C_DRIVERID_SAA7114,
+static const struct i2c_device_id saa7114_id[] = {
+ { "saa7114_old", 0 }, /* "saa7114" maps to the saa7115 driver */
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7114_id);
- .attach_adapter = saa7114_attach_adapter,
- .detach_client = saa7114_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa7114",
+ .driverid = I2C_DRIVERID_SAA7114,
.command = saa7114_command,
+ .probe = saa7114_probe,
+ .remove = saa7114_remove,
+ .id_table = saa7114_id,
};
-
-static int __init
-saa7114_init (void)
-{
- return i2c_add_driver(&i2c_driver_saa7114);
-}
-
-static void __exit
-saa7114_exit (void)
-{
- i2c_del_driver(&i2c_driver_saa7114);
-}
-
-module_init(saa7114_init);
-module_exit(saa7114_exit);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index d0e83fe0ff5..cc02fb18efa 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -29,7 +29,7 @@
* Note: the saa7126 is identical to the saa7127, and the saa7128 is
* identical to the saa7129, except that the saa7126 and saa7128 have
* macrovision anti-taping support. This driver will almost certainly
- * work find for those chips, except of course for the missing anti-taping
+ * work fine for those chips, except of course for the missing anti-taping
* support.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index b686bfabbde..24918445294 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -996,7 +996,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
goto fail4;
}
printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
- dev->name,dev->video_dev->minor & 0x1f);
+ dev->name, dev->video_dev->num);
dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
@@ -1005,7 +1005,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (err < 0)
goto fail4;
printk(KERN_INFO "%s: registered device vbi%d\n",
- dev->name,dev->vbi_dev->minor & 0x1f);
+ dev->name, dev->vbi_dev->num);
if (card_has_radio(dev)) {
dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
@@ -1014,7 +1014,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (err < 0)
goto fail4;
printk(KERN_INFO "%s: registered device radio%d\n",
- dev->name,dev->radio_dev->minor & 0x1f);
+ dev->name, dev->radio_dev->num);
}
/* everything worked */
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 87c10983266..8c46115d4c7 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -535,11 +535,16 @@ static int configure_tda827x_fe(struct saa7134_dev *dev,
struct tda1004x_config *cdec_conf,
struct tda827x_config *tuner_conf)
{
- dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
- if (dev->dvb.frontend) {
+ struct videobuf_dvb_frontend *fe0;
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+
+ fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
if (cdec_conf->i2c_gate)
- dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
- if (dvb_attach(tda827x_attach, dev->dvb.frontend,
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+ if (dvb_attach(tda827x_attach, fe0->dvb.frontend,
cdec_conf->tuner_address,
&dev->i2c_adap, tuner_conf))
return 0;
@@ -944,12 +949,30 @@ static int dvb_init(struct saa7134_dev *dev)
{
int ret;
int attach_xc3028 = 0;
+ struct videobuf_dvb_frontend *fe0;
+
+ /* FIXME: add support for multi-frontend */
+ mutex_init(&dev->frontends.lock);
+ INIT_LIST_HEAD(&dev->frontends.felist);
+ dev->frontends.active_fe_id = 0;
+
+ printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
+
+ if (videobuf_dvb_alloc_frontend(&dev->frontends, 1) == NULL) {
+ printk(KERN_ERR "%s() failed to alloc\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
/* init struct videobuf_dvb */
dev->ts.nr_bufs = 32;
dev->ts.nr_packets = 32*4;
- dev->dvb.name = dev->name;
- videobuf_queue_sg_init(&dev->dvb.dvbq, &saa7134_ts_qops,
+ fe0->dvb.name = dev->name;
+ videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
@@ -959,47 +982,47 @@ static int dvb_init(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
dprintk("pinnacle 300i dvb setup\n");
- dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
+ fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
}
break;
case SAA7134_BOARD_AVERMEDIA_777:
case SAA7134_BOARD_AVERMEDIA_A16AR:
dprintk("avertv 777 dvb setup\n");
- dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
+ fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0x61,
TUNER_PHILIPS_TD1316);
}
break;
case SAA7134_BOARD_AVERMEDIA_A16D:
dprintk("AverMedia A16D dvb setup\n");
- dev->dvb.frontend = dvb_attach(mt352_attach,
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
&avermedia_xc3028_mt352_dev,
&dev->i2c_adap);
attach_xc3028 = 1;
break;
case SAA7134_BOARD_MD7134:
- dev->dvb.frontend = dvb_attach(tda10046_attach,
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
&medion_cardbus,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&dev->i2c_adap, medion_cardbus.tuner_address,
TUNER_PHILIPS_FMD1216ME_MK3);
}
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
- dev->dvb.frontend = dvb_attach(tda10046_attach,
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_tu1216_60_config,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
}
break;
case SAA7134_BOARD_FLYDVBTDUO:
@@ -1010,24 +1033,24 @@ static int dvb_init(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
- dev->dvb.frontend = dvb_attach(tda10046_attach,
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_europa_config,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
- dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
- dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
- dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
- dev->dvb.frontend = dvb_attach(tda10046_attach,
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_tu1216_61_config,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
}
break;
case SAA7134_BOARD_KWORLD_DVBT_210:
@@ -1066,14 +1089,14 @@ static int dvb_init(struct saa7134_dev *dev)
&tda827x_cfg_0) < 0)
goto dettach_frontend;
} else { /* satellite */
- dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
- if (dev->dvb.frontend) {
- if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
+ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
goto dettach_frontend;
}
- if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
+ if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap,
0x08, 0, 0) == NULL) {
wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
goto dettach_frontend;
@@ -1083,11 +1106,11 @@ static int dvb_init(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
- dev->dvb.frontend = dvb_attach(tda10046_attach,
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
&ads_tech_duo_config,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- if (dvb_attach(tda827x_attach,dev->dvb.frontend,
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda827x_attach,fe0->dvb.frontend,
ads_tech_duo_config.tuner_address, &dev->i2c_adap,
&ads_duo_cfg) == NULL) {
wprintk("no tda827x tuner found at addr: %02x\n",
@@ -1108,15 +1131,15 @@ static int dvb_init(struct saa7134_dev *dev)
&tda827x_cfg_0) < 0)
goto dettach_frontend;
} else { /* satellite */
- dev->dvb.frontend = dvb_attach(tda10086_attach,
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
&flydvbs, &dev->i2c_adap);
- if (dev->dvb.frontend) {
- struct dvb_frontend *fe = dev->dvb.frontend;
+ if (fe0->dvb.frontend) {
+ struct dvb_frontend *fe = fe0->dvb.frontend;
u8 dev_id = dev->eedata[2];
u8 data = 0xc4;
struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
- if (dvb_attach(tda826x_attach, dev->dvb.frontend,
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend,
0x60, &dev->i2c_adap, 0) == NULL) {
wprintk("%s: Medion Quadro, no tda826x "
"found !\n", __func__);
@@ -1150,31 +1173,31 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
- dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
+ fe0->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
&dev->i2c_adap);
- if (dev->dvb.frontend)
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ if (fe0->dvb.frontend)
+ dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61,
NULL, DVB_PLL_TDHU2);
break;
case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
case SAA7134_BOARD_KWORLD_ATSC110:
- dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
+ fe0->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
&dev->i2c_adap);
- if (dev->dvb.frontend)
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ if (fe0->dvb.frontend)
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0x61,
TUNER_PHILIPS_TUV1236D);
break;
case SAA7134_BOARD_FLYDVBS_LR300:
- dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: No tda826x found!\n", __func__);
goto dettach_frontend;
}
- if (dvb_attach(isl6421_attach, dev->dvb.frontend,
+ if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0x08, 0, 0) == NULL) {
wprintk("%s: No ISL6421 found!\n", __func__);
goto dettach_frontend;
@@ -1182,25 +1205,25 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
- dev->dvb.frontend = dvb_attach(tda10046_attach,
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
&medion_cardbus,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
- dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&dev->i2c_adap, medion_cardbus.tuner_address,
TUNER_PHILIPS_FMD1216ME_MK3);
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
- dev->dvb.frontend = dvb_attach(tda10046_attach,
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_europa_config,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
}
break;
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
@@ -1239,15 +1262,15 @@ static int dvb_init(struct saa7134_dev *dev)
goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_SNAKE:
- dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
- if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: No tda826x found!\n", __func__);
goto dettach_frontend;
}
- if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
+ if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0, 0) == NULL) {
wprintk("%s: No lnbp21 found!\n", __func__);
goto dettach_frontend;
@@ -1269,24 +1292,24 @@ static int dvb_init(struct saa7134_dev *dev)
saa7134_set_gpio(dev, 25, 0);
msleep(10);
saa7134_set_gpio(dev, 25, 1);
- dev->dvb.frontend = dvb_attach(mt352_attach,
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
&avermedia_xc3028_mt352_dev,
&dev->i2c_adap);
attach_xc3028 = 1;
break;
case SAA7134_BOARD_MD7134_BRIDGE_2:
- dev->dvb.frontend = dvb_attach(tda10086_attach,
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
&sd1878_4m, &dev->i2c_adap);
- if (dev->dvb.frontend) {
+ if (fe0->dvb.frontend) {
struct dvb_frontend *fe;
- if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+ if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
&dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
wprintk("%s: MD7134 DVB-S, no SD1878 "
"found !\n", __func__);
goto dettach_frontend;
}
/* we need to open the i2c gate (we know it exists) */
- fe = dev->dvb.frontend;
+ fe = fe0->dvb.frontend;
fe->ops.i2c_gate_ctrl(fe, 1);
if (dvb_attach(isl6405_attach, fe,
&dev->i2c_adap, 0x08, 0, 0) == NULL) {
@@ -1305,7 +1328,7 @@ static int dvb_init(struct saa7134_dev *dev)
saa7134_set_gpio(dev, 25, 0);
msleep(10);
saa7134_set_gpio(dev, 25, 1);
- dev->dvb.frontend = dvb_attach(mt352_attach,
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
&avermedia_xc3028_mt352_dev,
&dev->i2c_adap);
attach_xc3028 = 1;
@@ -1316,17 +1339,17 @@ static int dvb_init(struct saa7134_dev *dev)
&tda827x_cfg_2) < 0)
goto dettach_frontend;
} else { /* satellite */
- dev->dvb.frontend = dvb_attach(tda10086_attach,
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
&flydvbs, &dev->i2c_adap);
- if (dev->dvb.frontend) {
+ if (fe0->dvb.frontend) {
if (dvb_attach(tda826x_attach,
- dev->dvb.frontend, 0x60,
+ fe0->dvb.frontend, 0x60,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: Asus Tiger 3in1, no "
"tda826x found!\n", __func__);
goto dettach_frontend;
}
- if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
+ if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0, 0) == NULL) {
wprintk("%s: Asus Tiger 3in1, no lnbp21"
" found!\n", __func__);
@@ -1352,10 +1375,10 @@ static int dvb_init(struct saa7134_dev *dev)
.i2c_addr = 0x61,
};
- if (!dev->dvb.frontend)
+ if (!fe0->dvb.frontend)
return -1;
- fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
if (!fe) {
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
dev->name);
@@ -1363,40 +1386,47 @@ static int dvb_init(struct saa7134_dev *dev)
}
}
- if (NULL == dev->dvb.frontend) {
+ if (NULL == fe0->dvb.frontend) {
printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
return -1;
}
/* define general-purpose callback pointer */
- dev->dvb.frontend->callback = saa7134_tuner_callback;
+ fe0->dvb.frontend->callback = saa7134_tuner_callback;
/* register everything else */
- ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev,
- adapter_nr);
+ ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ &dev->pci->dev, adapter_nr, 0);
/* this sequence is necessary to make the tda1004x load its firmware
* and to enter analog mode of hybrid boards
*/
if (!ret) {
- if (dev->dvb.frontend->ops.init)
- dev->dvb.frontend->ops.init(dev->dvb.frontend);
- if (dev->dvb.frontend->ops.sleep)
- dev->dvb.frontend->ops.sleep(dev->dvb.frontend);
- if (dev->dvb.frontend->ops.tuner_ops.sleep)
- dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend);
+ if (fe0->dvb.frontend->ops.init)
+ fe0->dvb.frontend->ops.init(fe0->dvb.frontend);
+ if (fe0->dvb.frontend->ops.sleep)
+ fe0->dvb.frontend->ops.sleep(fe0->dvb.frontend);
+ if (fe0->dvb.frontend->ops.tuner_ops.sleep)
+ fe0->dvb.frontend->ops.tuner_ops.sleep(fe0->dvb.frontend);
}
return ret;
dettach_frontend:
- if (dev->dvb.frontend)
- dvb_frontend_detach(dev->dvb.frontend);
- dev->dvb.frontend = NULL;
+ if (fe0->dvb.frontend)
+ dvb_frontend_detach(fe0->dvb.frontend);
+ fe0->dvb.frontend = NULL;
return -1;
}
static int dvb_fini(struct saa7134_dev *dev)
{
+ struct videobuf_dvb_frontend *fe0;
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
/* FIXME: I suspect that this code is bogus, since the entry for
Pinnacle 300I DVB-T PAL already defines the proper init to allow
the detection of mt2032 (TDA9887_PORT2_INACTIVE)
@@ -1416,7 +1446,7 @@ static int dvb_fini(struct saa7134_dev *dev)
u8 data = 0x80;
struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
struct dvb_frontend *fe;
- fe = dev->dvb.frontend;
+ fe = fe0->dvb.frontend;
if (fe->ops.i2c_gate_ctrl) {
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
@@ -1424,8 +1454,8 @@ static int dvb_fini(struct saa7134_dev *dev)
}
}
}
- if (dev->dvb.frontend)
- videobuf_dvb_unregister(&dev->dvb);
+ if (fe0->dvb.frontend)
+ videobuf_dvb_unregister_bus(&dev->frontends);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 9a8766a78a0..7f40511bcc0 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -534,7 +534,7 @@ static int empress_init(struct saa7134_dev *dev)
return err;
}
printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
- dev->name,dev->empress_dev->minor & 0x1f);
+ dev->name, dev->empress_dev->num);
videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops,
&dev->pci->dev, &dev->slock,
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 491ab1f8fdd..24096d6e1ef 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -581,7 +581,7 @@ struct saa7134_dev {
#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
/* SAA7134_MPEG_DVB only */
- struct videobuf_dvb dvb;
+ struct videobuf_dvb_frontends frontends;
int (*original_demod_sleep)(struct dvb_frontend *fe);
int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 02fda4eecea..6debb65152e 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -25,43 +25,25 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
#include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
#include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/videodev.h>
#include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#define I2C_NAME(s) (s)->name
-
-
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
/* ----------------------------------------------------------------------- */
struct saa7185 {
@@ -75,32 +57,24 @@ struct saa7185 {
int sat;
};
-#define I2C_SAA7185 0x88
-
/* ----------------------------------------------------------------------- */
-static inline int
-saa7185_read (struct i2c_client *client)
+static inline int saa7185_read(struct i2c_client *client)
{
return i2c_smbus_read_byte(client);
}
-static int
-saa7185_write (struct i2c_client *client,
- u8 reg,
- u8 value)
+static int saa7185_write(struct i2c_client *client, u8 reg, u8 value)
{
struct saa7185 *encoder = i2c_get_clientdata(client);
- dprintk(1, KERN_DEBUG "SAA7185: %02x set to %02x\n", reg, value);
+ v4l_dbg(1, debug, client, "%02x set to %02x\n", reg, value);
encoder->reg[reg] = value;
return i2c_smbus_write_byte_data(client, reg, value);
}
-static int
-saa7185_write_block (struct i2c_client *client,
- const u8 *data,
- unsigned int len)
+static int saa7185_write_block(struct i2c_client *client,
+ const u8 *data, unsigned int len)
{
int ret = -1;
u8 reg;
@@ -121,18 +95,17 @@ saa7185_write_block (struct i2c_client *client,
encoder->reg[reg++] = data[1];
len -= 2;
data += 2;
- } while (len >= 2 && data[0] == reg &&
- block_len < 32);
- if ((ret = i2c_master_send(client, block_data,
- block_len)) < 0)
+ } while (len >= 2 && data[0] == reg && block_len < 32);
+ ret = i2c_master_send(client, block_data, block_len);
+ if (ret < 0)
break;
}
} else {
/* do some slow I2C emulation kind of thing */
while (len >= 2) {
reg = *data++;
- if ((ret = saa7185_write(client, reg,
- *data++)) < 0)
+ ret = saa7185_write(client, reg, *data++);
+ if (ret < 0)
break;
len -= 2;
}
@@ -240,15 +213,11 @@ static const unsigned char init_ntsc[] = {
0x66, 0x21, /* FSC3 */
};
-static int
-saa7185_command (struct i2c_client *client,
- unsigned int cmd,
- void *arg)
+static int saa7185_command(struct i2c_client *client, unsigned cmd, void *arg)
{
struct saa7185 *encoder = i2c_get_clientdata(client);
switch (cmd) {
-
case 0:
saa7185_write_block(client, init_common,
sizeof(init_common));
@@ -264,7 +233,6 @@ saa7185_command (struct i2c_client *client,
sizeof(init_pal));
break;
}
-
break;
case ENCODER_GET_CAPABILITIES:
@@ -276,8 +244,8 @@ saa7185_command (struct i2c_client *client,
VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR;
cap->inputs = 1;
cap->outputs = 1;
- }
break;
+ }
case ENCODER_SET_NORM:
{
@@ -286,7 +254,6 @@ saa7185_command (struct i2c_client *client,
//saa7185_write_block(client, init_common, sizeof(init_common));
switch (*iarg) {
-
case VIDEO_MODE_NTSC:
saa7185_write_block(client, init_ntsc,
sizeof(init_ntsc));
@@ -300,11 +267,10 @@ saa7185_command (struct i2c_client *client,
case VIDEO_MODE_SECAM:
default:
return -EINVAL;
-
}
encoder->norm = *iarg;
- }
break;
+ }
case ENCODER_SET_INPUT:
{
@@ -314,7 +280,6 @@ saa7185_command (struct i2c_client *client,
*iarg = 1: input is from ZR36060 */
switch (*iarg) {
-
case 0:
/* Switch RTCE to 1 */
saa7185_write(client, 0x61,
@@ -332,21 +297,19 @@ saa7185_command (struct i2c_client *client,
default:
return -EINVAL;
-
}
- }
break;
+ }
case ENCODER_SET_OUTPUT:
{
int *iarg = arg;
/* not much choice of outputs */
- if (*iarg != 0) {
+ if (*iarg != 0)
return -EINVAL;
- }
- }
break;
+ }
case ENCODER_ENABLE_OUTPUT:
{
@@ -356,8 +319,8 @@ saa7185_command (struct i2c_client *client,
saa7185_write(client, 0x61,
(encoder->reg[0x61] & 0xbf) |
(encoder->enable ? 0x00 : 0x40));
- }
break;
+ }
default:
return -EINVAL;
@@ -368,138 +331,65 @@ saa7185_command (struct i2c_client *client,
/* ----------------------------------------------------------------------- */
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-static unsigned short ignore = I2C_CLIENT_END;
+I2C_CLIENT_INSMOD;
-static struct i2c_client_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .probe = &ignore,
- .ignore = &ignore,
-};
-
-static struct i2c_driver i2c_driver_saa7185;
-
-static int
-saa7185_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
+static int saa7185_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int i;
- struct i2c_client *client;
struct saa7185 *encoder;
- dprintk(1,
- KERN_INFO
- "saa7185.c: detecting saa7185 client on address 0x%x\n",
- address << 1);
-
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return 0;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_saa7185;
- strlcpy(I2C_NAME(client), "saa7185", sizeof(I2C_NAME(client)));
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
- if (encoder == NULL) {
- kfree(client);
+ if (encoder == NULL)
return -ENOMEM;
- }
encoder->norm = VIDEO_MODE_NTSC;
encoder->enable = 1;
i2c_set_clientdata(client, encoder);
- i = i2c_attach_client(client);
- if (i) {
- kfree(client);
- kfree(encoder);
- return i;
- }
-
i = saa7185_write_block(client, init_common, sizeof(init_common));
- if (i >= 0) {
- i = saa7185_write_block(client, init_ntsc,
- sizeof(init_ntsc));
- }
- if (i < 0) {
- dprintk(1, KERN_ERR "%s_attach: init error %d\n",
- I2C_NAME(client), i);
- } else {
- dprintk(1,
- KERN_INFO
- "%s_attach: chip version %d at address 0x%x\n",
- I2C_NAME(client), saa7185_read(client) >> 5,
- client->addr << 1);
- }
-
+ if (i >= 0)
+ i = saa7185_write_block(client, init_ntsc, sizeof(init_ntsc));
+ if (i < 0)
+ v4l_dbg(1, debug, client, "init error %d\n", i);
+ else
+ v4l_dbg(1, debug, client, "revision 0x%x\n",
+ saa7185_read(client) >> 5);
return 0;
}
-static int
-saa7185_attach_adapter (struct i2c_adapter *adapter)
-{
- dprintk(1,
- KERN_INFO
- "saa7185.c: starting probe for adapter %s (0x%x)\n",
- I2C_NAME(adapter), adapter->id);
- return i2c_probe(adapter, &addr_data, &saa7185_detect_client);
-}
-
-static int
-saa7185_detach_client (struct i2c_client *client)
+static int saa7185_remove(struct i2c_client *client)
{
struct saa7185 *encoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
saa7185_write(client, 0x61, (encoder->reg[0x61]) | 0x40); /* SW: output off is active */
//saa7185_write(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */
kfree(encoder);
- kfree(client);
-
return 0;
}
/* ----------------------------------------------------------------------- */
-static struct i2c_driver i2c_driver_saa7185 = {
- .driver = {
- .name = "saa7185", /* name */
- },
-
- .id = I2C_DRIVERID_SAA7185B,
+static const struct i2c_device_id saa7185_id[] = {
+ { "saa7185", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7185_id);
- .attach_adapter = saa7185_attach_adapter,
- .detach_client = saa7185_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa7185",
+ .driverid = I2C_DRIVERID_SAA7185B,
.command = saa7185_command,
+ .probe = saa7185_probe,
+ .remove = saa7185_remove,
+ .id_table = saa7185_id,
};
-
-static int __init
-saa7185_init (void)
-{
- return i2c_add_driver(&i2c_driver_saa7185);
-}
-
-static void __exit
-saa7185_exit (void)
-{
- i2c_del_driver(&i2c_driver_saa7185);
-}
-
-module_init(saa7185_init);
-module_exit(saa7185_exit);
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index ae3949180c4..044a2e94c34 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -1412,7 +1412,7 @@ static int se401_probe(struct usb_interface *intf,
return -EIO;
}
dev_info(&intf->dev, "registered new video device: video%d\n",
- se401->vdev.minor);
+ se401->vdev.num);
usb_set_intfdata (intf, se401);
return 0;
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 76838091dc6..2407607f2ef 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -40,39 +40,39 @@
/* register offsets for sh7722 / sh7723 */
-#define CAPSR 0x00
-#define CAPCR 0x04
-#define CAMCR 0x08
-#define CMCYR 0x0c
-#define CAMOR 0x10
-#define CAPWR 0x14
-#define CAIFR 0x18
-#define CSTCR 0x20 /* not on sh7723 */
-#define CSECR 0x24 /* not on sh7723 */
-#define CRCNTR 0x28
-#define CRCMPR 0x2c
-#define CFLCR 0x30
-#define CFSZR 0x34
-#define CDWDR 0x38
-#define CDAYR 0x3c
-#define CDACR 0x40
-#define CDBYR 0x44
-#define CDBCR 0x48
-#define CBDSR 0x4c
-#define CFWCR 0x5c
-#define CLFCR 0x60
-#define CDOCR 0x64
-#define CDDCR 0x68
-#define CDDAR 0x6c
-#define CEIER 0x70
-#define CETCR 0x74
-#define CSTSR 0x7c
-#define CSRTR 0x80
-#define CDSSR 0x84
-#define CDAYR2 0x90
-#define CDACR2 0x94
-#define CDBYR2 0x98
-#define CDBCR2 0x9c
+#define CAPSR 0x00 /* Capture start register */
+#define CAPCR 0x04 /* Capture control register */
+#define CAMCR 0x08 /* Capture interface control register */
+#define CMCYR 0x0c /* Capture interface cycle register */
+#define CAMOR 0x10 /* Capture interface offset register */
+#define CAPWR 0x14 /* Capture interface width register */
+#define CAIFR 0x18 /* Capture interface input format register */
+#define CSTCR 0x20 /* Camera strobe control register (<= sh7722) */
+#define CSECR 0x24 /* Camera strobe emission count register (<= sh7722) */
+#define CRCNTR 0x28 /* CEU register control register */
+#define CRCMPR 0x2c /* CEU register forcible control register */
+#define CFLCR 0x30 /* Capture filter control register */
+#define CFSZR 0x34 /* Capture filter size clip register */
+#define CDWDR 0x38 /* Capture destination width register */
+#define CDAYR 0x3c /* Capture data address Y register */
+#define CDACR 0x40 /* Capture data address C register */
+#define CDBYR 0x44 /* Capture data bottom-field address Y register */
+#define CDBCR 0x48 /* Capture data bottom-field address C register */
+#define CBDSR 0x4c /* Capture bundle destination size register */
+#define CFWCR 0x5c /* Firewall operation control register */
+#define CLFCR 0x60 /* Capture low-pass filter control register */
+#define CDOCR 0x64 /* Capture data output control register */
+#define CDDCR 0x68 /* Capture data complexity level register */
+#define CDDAR 0x6c /* Capture data complexity level address register */
+#define CEIER 0x70 /* Capture event interrupt enable register */
+#define CETCR 0x74 /* Capture event flag clear register */
+#define CSTSR 0x7c /* Capture status register */
+#define CSRTR 0x80 /* Capture software reset register */
+#define CDSSR 0x84 /* Capture data size register */
+#define CDAYR2 0x90 /* Capture data address Y register 2 */
+#define CDACR2 0x94 /* Capture data address C register 2 */
+#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */
+#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */
static DEFINE_MUTEX(camera_lock);
@@ -165,6 +165,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
ceu_write(pcdev, CETCR, 0x0317f313 ^ 0x10);
if (pcdev->active) {
+ pcdev->active->state = VIDEOBUF_ACTIVE;
ceu_write(pcdev, CDAYR, videobuf_to_dma_contig(pcdev->active));
ceu_write(pcdev, CAPSR, 0x1); /* start capture */
}
@@ -236,7 +237,7 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
vb, vb->baddr, vb->bsize);
- vb->state = VIDEOBUF_ACTIVE;
+ vb->state = VIDEOBUF_QUEUED;
spin_lock_irqsave(&pcdev->lock, flags);
list_add_tail(&vb->queue, &pcdev->capture);
@@ -323,12 +324,24 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ unsigned long flags;
BUG_ON(icd != pcdev->icd);
/* disable capture, disable interrupts */
ceu_write(pcdev, CEIER, 0);
ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
+
+ /* make sure active buffer is canceled */
+ spin_lock_irqsave(&pcdev->lock, flags);
+ if (pcdev->active) {
+ list_del(&pcdev->active->queue);
+ pcdev->active->state = VIDEOBUF_ERROR;
+ wake_up_all(&pcdev->active->done);
+ pcdev->active = NULL;
+ }
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+
icd->ops->release(icd);
dev_info(&icd->dev,
@@ -391,7 +404,20 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
ceu_write(pcdev, CFLCR, 0); /* data fetch mode - no scaling */
ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width);
ceu_write(pcdev, CLFCR, 0); /* data fetch mode - no lowpass filter */
- ceu_write(pcdev, CDOCR, 0x00000016);
+
+ /* A few words about byte order (observed in Big Endian mode)
+ *
+ * In data fetch mode bytes are received in chunks of 8 bytes.
+ * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first)
+ *
+ * The data is however by default written to memory in reverse order:
+ * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte)
+ *
+ * The lowest three bits of CDOCR allows us to do swapping,
+ * using 7 we swap the data bytes to match the incoming order:
+ * D0, D1, D2, D3, D4, D5, D6, D7
+ */
+ ceu_write(pcdev, CDOCR, 0x00000017);
ceu_write(pcdev, CDWDR, cdwdr_width);
ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 20e30bd9364..fcd2b62f92c 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -1008,7 +1008,7 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "URB timeout reached. The camera is misconfigured. "
"To use it, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -EIO;
}
@@ -1734,7 +1734,7 @@ static void sn9c102_release_resources(struct kref *kref)
cam = container_of(kref, struct sn9c102_device, kref);
- DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+ DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
usb_put_dev(cam->usbdev);
@@ -1792,7 +1792,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
if (cam->users) {
DBG(2, "Device /dev/video%d is already in use",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
DBG(3, "Simultaneous opens are not supported");
/*
open() must follow the open flags and should block
@@ -1845,7 +1845,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
cam->frame_count = 0;
sn9c102_empty_framequeues(cam);
- DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+ DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num);
out:
mutex_unlock(&cam->open_mutex);
@@ -1870,7 +1870,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
cam->users--;
wake_up_interruptible_nr(&cam->wait_open, 1);
- DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+ DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num);
kref_put(&cam->kref, sn9c102_release_resources);
@@ -2432,7 +2432,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -EIO;
}
@@ -2445,7 +2445,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -ENOMEM;
}
@@ -2689,7 +2689,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -EIO;
}
@@ -2701,7 +2701,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -ENOMEM;
}
@@ -2748,7 +2748,7 @@ sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
"problems. To use the camera, close and open "
- "/dev/video%d again.", cam->v4ldev->minor);
+ "/dev/video%d again.", cam->v4ldev->num);
return -EIO;
}
@@ -3348,7 +3348,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+ DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num);
video_set_drvdata(cam->v4ldev, cam);
cam->module_param.force_munmap = force_munmap[dev_nr];
@@ -3402,7 +3402,7 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
"memory deallocation are deferred.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
cam->state |= DEV_MISCONFIGURED;
sn9c102_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index 1adc257ebdb..bb7a9d480e8 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -18,15 +18,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/soc_camera.h>
-
-struct soc_camera_platform_info {
- int iface;
- char *format_name;
- unsigned long format_depth;
- struct v4l2_pix_format format;
- unsigned long bus_param;
- int (*set_capture)(struct soc_camera_platform_info *info, int enable);
-};
+#include <media/soc_camera_platform.h>
struct soc_camera_platform_priv {
struct soc_camera_platform_info *info;
@@ -44,11 +36,21 @@ soc_camera_platform_get_info(struct soc_camera_device *icd)
static int soc_camera_platform_init(struct soc_camera_device *icd)
{
+ struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+
+ if (p->power)
+ p->power(1);
+
return 0;
}
static int soc_camera_platform_release(struct soc_camera_device *icd)
{
+ struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+
+ if (p->power)
+ p->power(0);
+
return 0;
}
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index db69bc5556d..e9eb6d754d5 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <linux/kref.h>
#include <linux/usb.h>
#include <linux/mm.h>
@@ -560,7 +559,7 @@ static void stk_clean_iso(struct stk_camera *dev)
urb = dev->isobufs[i].urb;
if (urb) {
- if (atomic_read(&dev->urbs_used))
+ if (atomic_read(&dev->urbs_used) && is_present(dev))
usb_kill_urb(urb);
usb_free_urb(urb);
}
@@ -689,18 +688,14 @@ static int v4l_stk_release(struct inode *inode, struct file *fp)
{
struct stk_camera *dev = fp->private_data;
- if (dev->owner != fp) {
- usb_autopm_put_interface(dev->interface);
- return 0;
+ if (dev->owner == fp) {
+ stk_stop_stream(dev);
+ stk_free_buffers(dev);
+ dev->owner = NULL;
}
- stk_stop_stream(dev);
-
- stk_free_buffers(dev);
-
- dev->owner = NULL;
-
- usb_autopm_put_interface(dev->interface);
+ if(is_present(dev))
+ usb_autopm_put_interface(dev->interface);
return 0;
}
@@ -714,9 +709,6 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
struct stk_sio_buffer *sbuf;
struct stk_camera *dev = fp->private_data;
- if (dev == NULL)
- return -EIO;
-
if (!is_present(dev))
return -EIO;
if (dev->owner && dev->owner != fp)
@@ -773,9 +765,6 @@ static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
{
struct stk_camera *dev = fp->private_data;
- if (dev == NULL)
- return -ENODEV;
-
poll_wait(fp, &dev->wait_frame, wait);
if (!is_present(dev))
@@ -1342,7 +1331,7 @@ static int stk_register_video_device(struct stk_camera *dev)
STK_ERROR("v4l registration failed\n");
else
STK_INFO("Syntek USB2.0 Camera is now controlling video device"
- " /dev/video%d\n", dev->vdev.minor);
+ " /dev/video%d\n", dev->vdev.num);
return err;
}
@@ -1436,8 +1425,8 @@ static void stk_camera_disconnect(struct usb_interface *interface)
wake_up_interruptible(&dev->wait_frame);
stk_remove_sysfs_files(&dev->vdev);
- STK_INFO("Syntek USB2.0 Camera release resources"
- "video device /dev/video%d\n", dev->vdev.minor);
+ STK_INFO("Syntek USB2.0 Camera release resources "
+ "video device /dev/video%d\n", dev->vdev.num);
video_unregister_device(&dev->vdev);
}
diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h
index 084a85bdd16..9f673663757 100644
--- a/drivers/media/video/stk-webcam.h
+++ b/drivers/media/video/stk-webcam.h
@@ -122,7 +122,6 @@ struct stk_camera {
#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
-void stk_camera_delete(struct kref *);
int stk_camera_write_reg(struct stk_camera *, u16, u8);
int stk_camera_read_reg(struct stk_camera *, u16, int *);
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index 9c549d93599..328c41b1517 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -1470,7 +1470,8 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
retval = -EIO;
goto error_vdev;
}
- PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor);
+ PDEBUG(0, "STV(i): registered new video device: video%d",
+ stv680->vdev->num);
usb_set_intfdata (intf, stv680);
retval = stv680_create_sysfs_files(stv680->vdev);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index bcc32fa92a8..3b0b84c2e45 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -242,7 +242,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "TCL M2523_3DBH_E"},
{ TUNER_ABSENT, "TCL M2523_3DIH_E"},
{ TUNER_ABSENT, "TCL MFPE05_2_U"},
- { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216MEX"},
+ { TUNER_PHILIPS_FMD1216MEX_MK3, "Philips FMD1216MEX"},
{ TUNER_ABSENT, "Philips FRH2036B"},
{ TUNER_ABSENT, "Panasonic ENGF75_01GF"},
{ TUNER_ABSENT, "MaxLinear MXL5005"},
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index e986c28b7bb..da27a528798 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -229,7 +229,8 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
cam->input = input_dev = input_allocate_device();
if (!input_dev) {
- warn("Not enough memory for camera's input device\n");
+ dev_warn(&dev->dev,
+ "Not enough memory for camera's input device\n");
return;
}
@@ -243,8 +244,9 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
error = input_register_device(cam->input);
if (error) {
- warn("Failed to register camera's input device, err: %d\n",
- error);
+ dev_warn(&dev->dev,
+ "Failed to register camera's input device, err: %d\n",
+ error);
input_free_device(cam->input);
cam->input = NULL;
}
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index 05c61b52311..4459b8a7f81 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -93,7 +93,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
cam->input = input_dev = input_allocate_device();
if (!input_dev) {
- warn("insufficient mem for cam input device");
+ dev_warn(&dev->dev, "insufficient mem for cam input device\n");
return;
}
@@ -107,8 +107,9 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
error = input_register_device(cam->input);
if (error) {
- warn("Failed to register camera's input device, err: %d\n",
- error);
+ dev_warn(&dev->dev,
+ "Failed to register camera's input device, err: %d\n",
+ error);
input_free_device(cam->input);
cam->input = NULL;
}
@@ -587,8 +588,9 @@ static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
dataurb->iso_frame_desc[i].offset;
if (st < 0) {
- warn("Data error: packet=%d. len=%d. status=%d.",
- i, n, st);
+ dev_warn(&uvd->dev->dev,
+ "Data error: packet=%d. len=%d. status=%d.\n",
+ i, n, st);
uvd->stats.iso_err_count++;
continue;
}
@@ -699,7 +701,7 @@ static void qcm_stop_data(struct uvd *uvd)
ret = qcm_camera_off(uvd);
if (ret)
- warn("couldn't turn the cam off.");
+ dev_warn(&uvd->dev->dev, "couldn't turn the cam off.\n");
uvd->streaming = 0;
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index 07cd87d16f6..7c575bb8184 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -1059,7 +1059,7 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
dev_info(&uvd->dev->dev, "%s on /dev/video%d: canvas=%s videosize=%s\n",
(uvd->handle != NULL) ? uvd->handle->drvName : "???",
- uvd->vdev.minor, tmp2, tmp1);
+ uvd->vdev.num, tmp2, tmp1);
usb_get_dev(uvd->dev);
return 0;
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 7a127d6bfde..8e2d58bec48 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -877,7 +877,8 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
return -EIO;
}
- printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
+ printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",
+ cam->vdev.num);
usb_set_intfdata (intf, cam);
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 92427fdc145..9907b9aff2b 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -236,7 +236,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
sizeof(struct i2c_client));
sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name),
- " #%d", usbvision->vdev->minor & 0x1f);
+ " #%d", usbvision->vdev->num);
PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
usbvision->i2c_adap.dev.parent = &usbvision->dev->dev;
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 77aeb39b275..d185b57fdcd 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -1440,7 +1440,7 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
// vbi Device:
if (usbvision->vbi) {
PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]",
- usbvision->vbi->minor & 0x1f);
+ usbvision->vbi->num);
if (usbvision->vbi->minor != -1) {
video_unregister_device(usbvision->vbi);
} else {
@@ -1452,7 +1452,7 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
// Radio Device:
if (usbvision->rdev) {
PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]",
- usbvision->rdev->minor & 0x1f);
+ usbvision->rdev->num);
if (usbvision->rdev->minor != -1) {
video_unregister_device(usbvision->rdev);
} else {
@@ -1464,7 +1464,7 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
// Video Device:
if (usbvision->vdev) {
PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]",
- usbvision->vdev->minor & 0x1f);
+ usbvision->vdev->num);
if (usbvision->vdev->minor != -1) {
video_unregister_device(usbvision->vdev);
} else {
@@ -1490,7 +1490,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
goto err_exit;
}
printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n",
- usbvision->nr,usbvision->vdev->minor & 0x1f);
+ usbvision->nr, usbvision->vdev->num);
// Radio Device:
if (usbvision_device_data[usbvision->DevModel].Radio) {
@@ -1507,7 +1507,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
goto err_exit;
}
printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n",
- usbvision->nr, usbvision->rdev->minor & 0x1f);
+ usbvision->nr, usbvision->rdev->num);
}
// vbi Device:
if (usbvision_device_data[usbvision->DevModel].vbi) {
@@ -1523,7 +1523,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
goto err_exit;
}
printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n",
- usbvision->nr,usbvision->vbi->minor & 0x1f);
+ usbvision->nr, usbvision->vbi->num);
}
// all done
return 0;
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 78e4c4e09d8..758dfefaba8 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -464,7 +464,7 @@ static int uvc_v4l2_release(struct inode *inode, struct file *file)
return 0;
}
-static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
+static int __uvc_v4l2_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
@@ -978,8 +978,8 @@ static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
return uvc_xu_ctrl_query(video, arg, 1);
default:
- if ((ret = v4l_compat_translate_ioctl(inode, file, cmd, arg,
- uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
+ if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
+ __uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
cmd);
return ret;
@@ -988,6 +988,12 @@ static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
return ret;
}
+static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ return __uvc_v4l2_do_ioctl(file, cmd, arg);
+}
+
static int uvc_v4l2_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 928cb403737..f13c0a9d684 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -57,8 +57,7 @@ MODULE_LICENSE("GPL");
*/
static int
-get_v4l_control(struct inode *inode,
- struct file *file,
+get_v4l_control(struct file *file,
int cid,
v4l2_kioctl drv)
{
@@ -67,12 +66,12 @@ get_v4l_control(struct inode *inode,
int err;
qctrl2.id = cid;
- err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2);
+ err = drv(file, VIDIOC_QUERYCTRL, &qctrl2);
if (err < 0)
dprintk("VIDIOC_QUERYCTRL: %d\n", err);
if (err == 0 && !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) {
ctrl2.id = qctrl2.id;
- err = drv(inode, file, VIDIOC_G_CTRL, &ctrl2);
+ err = drv(file, VIDIOC_G_CTRL, &ctrl2);
if (err < 0) {
dprintk("VIDIOC_G_CTRL: %d\n", err);
return 0;
@@ -85,8 +84,7 @@ get_v4l_control(struct inode *inode,
}
static int
-set_v4l_control(struct inode *inode,
- struct file *file,
+set_v4l_control(struct file *file,
int cid,
int value,
v4l2_kioctl drv)
@@ -96,7 +94,7 @@ set_v4l_control(struct inode *inode,
int err;
qctrl2.id = cid;
- err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2);
+ err = drv(file, VIDIOC_QUERYCTRL, &qctrl2);
if (err < 0)
dprintk("VIDIOC_QUERYCTRL: %d\n", err);
if (err == 0 &&
@@ -114,7 +112,7 @@ set_v4l_control(struct inode *inode,
+ 32767)
/ 65535;
ctrl2.value += qctrl2.minimum;
- err = drv(inode, file, VIDIOC_S_CTRL, &ctrl2);
+ err = drv(file, VIDIOC_S_CTRL, &ctrl2);
if (err < 0)
dprintk("VIDIOC_S_CTRL: %d\n", err);
}
@@ -222,7 +220,6 @@ static int poll_one(struct file *file, struct poll_wqueues *pwq)
}
static int count_inputs(
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -232,14 +229,13 @@ static int count_inputs(
for (i = 0;; i++) {
memset(&input2, 0, sizeof(input2));
input2.index = i;
- if (0 != drv(inode, file, VIDIOC_ENUMINPUT, &input2))
+ if (0 != drv(file, VIDIOC_ENUMINPUT, &input2))
break;
}
return i;
}
static int check_size(
- struct inode *inode,
struct file *file,
v4l2_kioctl drv,
int *maxw,
@@ -252,14 +248,14 @@ static int check_size(
memset(&fmt2, 0, sizeof(fmt2));
desc2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (0 != drv(inode, file, VIDIOC_ENUM_FMT, &desc2))
+ if (0 != drv(file, VIDIOC_ENUM_FMT, &desc2))
goto done;
fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt2.fmt.pix.width = 10000;
fmt2.fmt.pix.height = 10000;
fmt2.fmt.pix.pixelformat = desc2.pixelformat;
- if (0 != drv(inode, file, VIDIOC_TRY_FMT, &fmt2))
+ if (0 != drv(file, VIDIOC_TRY_FMT, &fmt2))
goto done;
*maxw = fmt2.fmt.pix.width;
@@ -273,7 +269,6 @@ done:
static noinline int v4l1_compat_get_capabilities(
struct video_capability *cap,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -289,13 +284,13 @@ static noinline int v4l1_compat_get_capabilities(
memset(cap, 0, sizeof(*cap));
memset(&fbuf, 0, sizeof(fbuf));
- err = drv(inode, file, VIDIOC_QUERYCAP, cap2);
+ err = drv(file, VIDIOC_QUERYCAP, cap2);
if (err < 0) {
dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n", err);
goto done;
}
if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) {
- err = drv(inode, file, VIDIOC_G_FBUF, &fbuf);
+ err = drv(file, VIDIOC_G_FBUF, &fbuf);
if (err < 0) {
dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n", err);
memset(&fbuf, 0, sizeof(fbuf));
@@ -317,8 +312,8 @@ static noinline int v4l1_compat_get_capabilities(
if (fbuf.capability & V4L2_FBUF_CAP_LIST_CLIPPING)
cap->type |= VID_TYPE_CLIPPING;
- cap->channels = count_inputs(inode, file, drv);
- check_size(inode, file, drv,
+ cap->channels = count_inputs(file, drv);
+ check_size(file, drv,
&cap->maxwidth, &cap->maxheight);
cap->audios = 0; /* FIXME */
cap->minwidth = 48; /* FIXME */
@@ -331,7 +326,6 @@ done:
static noinline int v4l1_compat_get_frame_buffer(
struct video_buffer *buffer,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -341,7 +335,7 @@ static noinline int v4l1_compat_get_frame_buffer(
memset(buffer, 0, sizeof(*buffer));
memset(&fbuf, 0, sizeof(fbuf));
- err = drv(inode, file, VIDIOC_G_FBUF, &fbuf);
+ err = drv(file, VIDIOC_G_FBUF, &fbuf);
if (err < 0) {
dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n", err);
goto done;
@@ -386,7 +380,6 @@ done:
static noinline int v4l1_compat_set_frame_buffer(
struct video_buffer *buffer,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -415,7 +408,7 @@ static noinline int v4l1_compat_set_frame_buffer(
break;
}
fbuf.fmt.bytesperline = buffer->bytesperline;
- err = drv(inode, file, VIDIOC_S_FBUF, &fbuf);
+ err = drv(file, VIDIOC_S_FBUF, &fbuf);
if (err < 0)
dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %d\n", err);
return err;
@@ -423,7 +416,6 @@ static noinline int v4l1_compat_set_frame_buffer(
static noinline int v4l1_compat_get_win_cap_dimensions(
struct video_window *win,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -438,7 +430,7 @@ static noinline int v4l1_compat_get_win_cap_dimensions(
memset(win, 0, sizeof(*win));
fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
- err = drv(inode, file, VIDIOC_G_FMT, fmt);
+ err = drv(file, VIDIOC_G_FMT, fmt);
if (err < 0)
dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %d\n", err);
if (err == 0) {
@@ -453,7 +445,7 @@ static noinline int v4l1_compat_get_win_cap_dimensions(
}
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_G_FMT, fmt);
+ err = drv(file, VIDIOC_G_FMT, fmt);
if (err < 0) {
dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %d\n", err);
goto done;
@@ -472,7 +464,6 @@ done:
static noinline int v4l1_compat_set_win_cap_dimensions(
struct video_window *win,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -485,8 +476,8 @@ static noinline int v4l1_compat_set_win_cap_dimensions(
return err;
}
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- drv(inode, file, VIDIOC_STREAMOFF, &fmt->type);
- err1 = drv(inode, file, VIDIOC_G_FMT, fmt);
+ drv(file, VIDIOC_STREAMOFF, &fmt->type);
+ err1 = drv(file, VIDIOC_G_FMT, fmt);
if (err1 < 0)
dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %d\n", err1);
if (err1 == 0) {
@@ -494,7 +485,7 @@ static noinline int v4l1_compat_set_win_cap_dimensions(
fmt->fmt.pix.height = win->height;
fmt->fmt.pix.field = V4L2_FIELD_ANY;
fmt->fmt.pix.bytesperline = 0;
- err = drv(inode, file, VIDIOC_S_FMT, fmt);
+ err = drv(file, VIDIOC_S_FMT, fmt);
if (err < 0)
dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n",
err);
@@ -511,7 +502,7 @@ static noinline int v4l1_compat_set_win_cap_dimensions(
fmt->fmt.win.chromakey = win->chromakey;
fmt->fmt.win.clips = (void __user *)win->clips;
fmt->fmt.win.clipcount = win->clipcount;
- err2 = drv(inode, file, VIDIOC_S_FMT, fmt);
+ err2 = drv(file, VIDIOC_S_FMT, fmt);
if (err2 < 0)
dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %d\n", err2);
@@ -525,7 +516,6 @@ static noinline int v4l1_compat_set_win_cap_dimensions(
static noinline int v4l1_compat_turn_preview_on_off(
int *on,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -536,9 +526,9 @@ static noinline int v4l1_compat_turn_preview_on_off(
/* dirty hack time. But v4l1 has no STREAMOFF
* equivalent in the API, and this one at
* least comes close ... */
- drv(inode, file, VIDIOC_STREAMOFF, &captype);
+ drv(file, VIDIOC_STREAMOFF, &captype);
}
- err = drv(inode, file, VIDIOC_OVERLAY, on);
+ err = drv(file, VIDIOC_OVERLAY, on);
if (err < 0)
dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %d\n", err);
return err;
@@ -546,7 +536,6 @@ static noinline int v4l1_compat_turn_preview_on_off(
static noinline int v4l1_compat_get_input_info(
struct video_channel *chan,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -556,7 +545,7 @@ static noinline int v4l1_compat_get_input_info(
memset(&input2, 0, sizeof(input2));
input2.index = chan->channel;
- err = drv(inode, file, VIDIOC_ENUMINPUT, &input2);
+ err = drv(file, VIDIOC_ENUMINPUT, &input2);
if (err < 0) {
dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: "
"channel=%d err=%d\n", chan->channel, err);
@@ -578,7 +567,7 @@ static noinline int v4l1_compat_get_input_info(
break;
}
chan->norm = 0;
- err = drv(inode, file, VIDIOC_G_STD, &sid);
+ err = drv(file, VIDIOC_G_STD, &sid);
if (err < 0)
dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %d\n", err);
if (err == 0) {
@@ -595,14 +584,13 @@ done:
static noinline int v4l1_compat_set_input(
struct video_channel *chan,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
int err;
v4l2_std_id sid = 0;
- err = drv(inode, file, VIDIOC_S_INPUT, &chan->channel);
+ err = drv(file, VIDIOC_S_INPUT, &chan->channel);
if (err < 0)
dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %d\n", err);
switch (chan->norm) {
@@ -617,7 +605,7 @@ static noinline int v4l1_compat_set_input(
break;
}
if (0 != sid) {
- err = drv(inode, file, VIDIOC_S_STD, &sid);
+ err = drv(file, VIDIOC_S_STD, &sid);
if (err < 0)
dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %d\n", err);
}
@@ -626,7 +614,6 @@ static noinline int v4l1_compat_set_input(
static noinline int v4l1_compat_get_picture(
struct video_picture *pict,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -639,19 +626,19 @@ static noinline int v4l1_compat_get_picture(
return err;
}
- pict->brightness = get_v4l_control(inode, file,
+ pict->brightness = get_v4l_control(file,
V4L2_CID_BRIGHTNESS, drv);
- pict->hue = get_v4l_control(inode, file,
+ pict->hue = get_v4l_control(file,
V4L2_CID_HUE, drv);
- pict->contrast = get_v4l_control(inode, file,
+ pict->contrast = get_v4l_control(file,
V4L2_CID_CONTRAST, drv);
- pict->colour = get_v4l_control(inode, file,
+ pict->colour = get_v4l_control(file,
V4L2_CID_SATURATION, drv);
- pict->whiteness = get_v4l_control(inode, file,
+ pict->whiteness = get_v4l_control(file,
V4L2_CID_WHITENESS, drv);
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_G_FMT, fmt);
+ err = drv(file, VIDIOC_G_FMT, fmt);
if (err < 0) {
dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n", err);
goto done;
@@ -669,7 +656,6 @@ done:
static noinline int v4l1_compat_set_picture(
struct video_picture *pict,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -685,15 +671,15 @@ static noinline int v4l1_compat_set_picture(
}
memset(&fbuf, 0, sizeof(fbuf));
- set_v4l_control(inode, file,
+ set_v4l_control(file,
V4L2_CID_BRIGHTNESS, pict->brightness, drv);
- set_v4l_control(inode, file,
+ set_v4l_control(file,
V4L2_CID_HUE, pict->hue, drv);
- set_v4l_control(inode, file,
+ set_v4l_control(file,
V4L2_CID_CONTRAST, pict->contrast, drv);
- set_v4l_control(inode, file,
+ set_v4l_control(file,
V4L2_CID_SATURATION, pict->colour, drv);
- set_v4l_control(inode, file,
+ set_v4l_control(file,
V4L2_CID_WHITENESS, pict->whiteness, drv);
/*
* V4L1 uses this ioctl to set both memory capture and overlay
@@ -703,7 +689,7 @@ static noinline int v4l1_compat_set_picture(
*/
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_G_FMT, fmt);
+ err = drv(file, VIDIOC_G_FMT, fmt);
/* If VIDIOC_G_FMT failed, then the driver likely doesn't
support memory capture. Trying to set the memory capture
parameters would be pointless. */
@@ -714,13 +700,13 @@ static noinline int v4l1_compat_set_picture(
palette_to_pixelformat(pict->palette)) {
fmt->fmt.pix.pixelformat = palette_to_pixelformat(
pict->palette);
- mem_err = drv(inode, file, VIDIOC_S_FMT, fmt);
+ mem_err = drv(file, VIDIOC_S_FMT, fmt);
if (mem_err < 0)
dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n",
mem_err);
}
- err = drv(inode, file, VIDIOC_G_FBUF, &fbuf);
+ err = drv(file, VIDIOC_G_FBUF, &fbuf);
/* If VIDIOC_G_FBUF failed, then the driver likely doesn't
support overlay. Trying to set the overlay parameters
would be quite pointless. */
@@ -731,7 +717,7 @@ static noinline int v4l1_compat_set_picture(
palette_to_pixelformat(pict->palette)) {
fbuf.fmt.pixelformat = palette_to_pixelformat(
pict->palette);
- ovl_err = drv(inode, file, VIDIOC_S_FBUF, &fbuf);
+ ovl_err = drv(file, VIDIOC_S_FBUF, &fbuf);
if (ovl_err < 0)
dprintk("VIDIOCSPICT / VIDIOC_S_FBUF: %d\n",
ovl_err);
@@ -752,7 +738,6 @@ static noinline int v4l1_compat_set_picture(
static noinline int v4l1_compat_get_tuner(
struct video_tuner *tun,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -762,7 +747,7 @@ static noinline int v4l1_compat_get_tuner(
v4l2_std_id sid;
memset(&tun2, 0, sizeof(tun2));
- err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
+ err = drv(file, VIDIOC_G_TUNER, &tun2);
if (err < 0) {
dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %d\n", err);
goto done;
@@ -778,7 +763,7 @@ static noinline int v4l1_compat_get_tuner(
for (i = 0; i < 64; i++) {
memset(&std2, 0, sizeof(std2));
std2.index = i;
- if (0 != drv(inode, file, VIDIOC_ENUMSTD, &std2))
+ if (0 != drv(file, VIDIOC_ENUMSTD, &std2))
break;
if (std2.id & V4L2_STD_PAL)
tun->flags |= VIDEO_TUNER_PAL;
@@ -788,7 +773,7 @@ static noinline int v4l1_compat_get_tuner(
tun->flags |= VIDEO_TUNER_SECAM;
}
- err = drv(inode, file, VIDIOC_G_STD, &sid);
+ err = drv(file, VIDIOC_G_STD, &sid);
if (err < 0)
dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %d\n", err);
if (err == 0) {
@@ -811,7 +796,6 @@ done:
static noinline int v4l1_compat_select_tuner(
struct video_tuner *tun,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -821,7 +805,7 @@ static noinline int v4l1_compat_select_tuner(
t.index = tun->tuner;
- err = drv(inode, file, VIDIOC_S_INPUT, &t);
+ err = drv(file, VIDIOC_S_INPUT, &t);
if (err < 0)
dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n", err);
return err;
@@ -829,7 +813,6 @@ static noinline int v4l1_compat_select_tuner(
static noinline int v4l1_compat_get_frequency(
unsigned long *freq,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -838,7 +821,7 @@ static noinline int v4l1_compat_get_frequency(
memset(&freq2, 0, sizeof(freq2));
freq2.tuner = 0;
- err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
+ err = drv(file, VIDIOC_G_FREQUENCY, &freq2);
if (err < 0)
dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %d\n", err);
if (0 == err)
@@ -848,7 +831,6 @@ static noinline int v4l1_compat_get_frequency(
static noinline int v4l1_compat_set_frequency(
unsigned long *freq,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -856,9 +838,9 @@ static noinline int v4l1_compat_set_frequency(
struct v4l2_frequency freq2;
memset(&freq2, 0, sizeof(freq2));
- drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
+ drv(file, VIDIOC_G_FREQUENCY, &freq2);
freq2.frequency = *freq;
- err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2);
+ err = drv(file, VIDIOC_S_FREQUENCY, &freq2);
if (err < 0)
dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %d\n", err);
return err;
@@ -866,7 +848,6 @@ static noinline int v4l1_compat_set_frequency(
static noinline int v4l1_compat_get_audio(
struct video_audio *aud,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -876,7 +857,7 @@ static noinline int v4l1_compat_get_audio(
struct v4l2_tuner tun2;
memset(&aud2, 0, sizeof(aud2));
- err = drv(inode, file, VIDIOC_G_AUDIO, &aud2);
+ err = drv(file, VIDIOC_G_AUDIO, &aud2);
if (err < 0) {
dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %d\n", err);
goto done;
@@ -886,27 +867,27 @@ static noinline int v4l1_compat_get_audio(
aud->name[sizeof(aud->name) - 1] = 0;
aud->audio = aud2.index;
aud->flags = 0;
- i = get_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME, drv);
+ i = get_v4l_control(file, V4L2_CID_AUDIO_VOLUME, drv);
if (i >= 0) {
aud->volume = i;
aud->flags |= VIDEO_AUDIO_VOLUME;
}
- i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, drv);
+ i = get_v4l_control(file, V4L2_CID_AUDIO_BASS, drv);
if (i >= 0) {
aud->bass = i;
aud->flags |= VIDEO_AUDIO_BASS;
}
- i = get_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, drv);
+ i = get_v4l_control(file, V4L2_CID_AUDIO_TREBLE, drv);
if (i >= 0) {
aud->treble = i;
aud->flags |= VIDEO_AUDIO_TREBLE;
}
- i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, drv);
+ i = get_v4l_control(file, V4L2_CID_AUDIO_BALANCE, drv);
if (i >= 0) {
aud->balance = i;
aud->flags |= VIDEO_AUDIO_BALANCE;
}
- i = get_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE, drv);
+ i = get_v4l_control(file, V4L2_CID_AUDIO_MUTE, drv);
if (i >= 0) {
if (i)
aud->flags |= VIDEO_AUDIO_MUTE;
@@ -914,13 +895,13 @@ static noinline int v4l1_compat_get_audio(
}
aud->step = 1;
qctrl2.id = V4L2_CID_AUDIO_VOLUME;
- if (drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2) == 0 &&
+ if (drv(file, VIDIOC_QUERYCTRL, &qctrl2) == 0 &&
!(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
aud->step = qctrl2.step;
aud->mode = 0;
memset(&tun2, 0, sizeof(tun2));
- err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
+ err = drv(file, VIDIOC_G_TUNER, &tun2);
if (err < 0) {
dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n", err);
err = 0;
@@ -939,7 +920,6 @@ done:
static noinline int v4l1_compat_set_audio(
struct video_audio *aud,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -951,24 +931,24 @@ static noinline int v4l1_compat_set_audio(
memset(&tun2, 0, sizeof(tun2));
aud2.index = aud->audio;
- err = drv(inode, file, VIDIOC_S_AUDIO, &aud2);
+ err = drv(file, VIDIOC_S_AUDIO, &aud2);
if (err < 0) {
dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %d\n", err);
goto done;
}
- set_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME,
+ set_v4l_control(file, V4L2_CID_AUDIO_VOLUME,
aud->volume, drv);
- set_v4l_control(inode, file, V4L2_CID_AUDIO_BASS,
+ set_v4l_control(file, V4L2_CID_AUDIO_BASS,
aud->bass, drv);
- set_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE,
+ set_v4l_control(file, V4L2_CID_AUDIO_TREBLE,
aud->treble, drv);
- set_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE,
+ set_v4l_control(file, V4L2_CID_AUDIO_BALANCE,
aud->balance, drv);
- set_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE,
+ set_v4l_control(file, V4L2_CID_AUDIO_MUTE,
!!(aud->flags & VIDEO_AUDIO_MUTE), drv);
- err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
+ err = drv(file, VIDIOC_G_TUNER, &tun2);
if (err < 0)
dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %d\n", err);
if (err == 0) {
@@ -985,7 +965,7 @@ static noinline int v4l1_compat_set_audio(
tun2.audmode = V4L2_TUNER_MODE_LANG2;
break;
}
- err = drv(inode, file, VIDIOC_S_TUNER, &tun2);
+ err = drv(file, VIDIOC_S_TUNER, &tun2);
if (err < 0)
dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %d\n", err);
}
@@ -996,7 +976,6 @@ done:
static noinline int v4l1_compat_capture_frame(
struct video_mmap *mm,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -1013,7 +992,7 @@ static noinline int v4l1_compat_capture_frame(
memset(&buf, 0, sizeof(buf));
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_G_FMT, fmt);
+ err = drv(file, VIDIOC_G_FMT, fmt);
if (err < 0) {
dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\n", err);
goto done;
@@ -1029,7 +1008,7 @@ static noinline int v4l1_compat_capture_frame(
palette_to_pixelformat(mm->format);
fmt->fmt.pix.field = V4L2_FIELD_ANY;
fmt->fmt.pix.bytesperline = 0;
- err = drv(inode, file, VIDIOC_S_FMT, fmt);
+ err = drv(file, VIDIOC_S_FMT, fmt);
if (err < 0) {
dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n", err);
goto done;
@@ -1037,17 +1016,17 @@ static noinline int v4l1_compat_capture_frame(
}
buf.index = mm->frame;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_QUERYBUF, &buf);
+ err = drv(file, VIDIOC_QUERYBUF, &buf);
if (err < 0) {
dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %d\n", err);
goto done;
}
- err = drv(inode, file, VIDIOC_QBUF, &buf);
+ err = drv(file, VIDIOC_QBUF, &buf);
if (err < 0) {
dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n", err);
goto done;
}
- err = drv(inode, file, VIDIOC_STREAMON, &captype);
+ err = drv(file, VIDIOC_STREAMON, &captype);
if (err < 0)
dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n", err);
done:
@@ -1057,7 +1036,6 @@ done:
static noinline int v4l1_compat_sync(
int *i,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -1069,7 +1047,7 @@ static noinline int v4l1_compat_sync(
memset(&buf, 0, sizeof(buf));
buf.index = *i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_QUERYBUF, &buf);
+ err = drv(file, VIDIOC_QUERYBUF, &buf);
if (err < 0) {
/* No such buffer */
dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err);
@@ -1082,7 +1060,7 @@ static noinline int v4l1_compat_sync(
}
/* make sure capture actually runs so we don't block forever */
- err = drv(inode, file, VIDIOC_STREAMON, &captype);
+ err = drv(file, VIDIOC_STREAMON, &captype);
if (err < 0) {
dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %d\n", err);
goto done;
@@ -1096,7 +1074,7 @@ static noinline int v4l1_compat_sync(
if (err < 0 || /* error or sleep was interrupted */
err == 0) /* timeout? Shouldn't occur. */
break;
- err = drv(inode, file, VIDIOC_QUERYBUF, &buf);
+ err = drv(file, VIDIOC_QUERYBUF, &buf);
if (err < 0)
dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err);
}
@@ -1104,7 +1082,7 @@ static noinline int v4l1_compat_sync(
if (!(buf.flags & V4L2_BUF_FLAG_DONE)) /* not done */
goto done;
do {
- err = drv(inode, file, VIDIOC_DQBUF, &buf);
+ err = drv(file, VIDIOC_DQBUF, &buf);
if (err < 0)
dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %d\n", err);
} while (err == 0 && buf.index != *i);
@@ -1114,7 +1092,6 @@ done:
static noinline int v4l1_compat_get_vbi_format(
struct vbi_format *fmt,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -1128,7 +1105,7 @@ static noinline int v4l1_compat_get_vbi_format(
}
fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- err = drv(inode, file, VIDIOC_G_FMT, fmt2);
+ err = drv(file, VIDIOC_G_FMT, fmt2);
if (err < 0) {
dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
goto done;
@@ -1153,7 +1130,6 @@ done:
static noinline int v4l1_compat_set_vbi_format(
struct vbi_format *fmt,
- struct inode *inode,
struct file *file,
v4l2_kioctl drv)
{
@@ -1179,7 +1155,7 @@ static noinline int v4l1_compat_set_vbi_format(
fmt2->fmt.vbi.start[1] = fmt->start[1];
fmt2->fmt.vbi.count[1] = fmt->count[1];
fmt2->fmt.vbi.flags = fmt->flags;
- err = drv(inode, file, VIDIOC_TRY_FMT, fmt2);
+ err = drv(file, VIDIOC_TRY_FMT, fmt2);
if (err < 0) {
dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %d\n", err);
goto done;
@@ -1196,7 +1172,7 @@ static noinline int v4l1_compat_set_vbi_format(
err = -EINVAL;
goto done;
}
- err = drv(inode, file, VIDIOC_S_FMT, fmt2);
+ err = drv(file, VIDIOC_S_FMT, fmt2);
if (err < 0)
dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err);
done:
@@ -1208,8 +1184,7 @@ done:
* This function is exported.
*/
int
-v4l_compat_translate_ioctl(struct inode *inode,
- struct file *file,
+v4l_compat_translate_ioctl(struct file *file,
int cmd,
void *arg,
v4l2_kioctl drv)
@@ -1218,64 +1193,64 @@ v4l_compat_translate_ioctl(struct inode *inode,
switch (cmd) {
case VIDIOCGCAP: /* capability */
- err = v4l1_compat_get_capabilities(arg, inode, file, drv);
+ err = v4l1_compat_get_capabilities(arg, file, drv);
break;
case VIDIOCGFBUF: /* get frame buffer */
- err = v4l1_compat_get_frame_buffer(arg, inode, file, drv);
+ err = v4l1_compat_get_frame_buffer(arg, file, drv);
break;
case VIDIOCSFBUF: /* set frame buffer */
- err = v4l1_compat_set_frame_buffer(arg, inode, file, drv);
+ err = v4l1_compat_set_frame_buffer(arg, file, drv);
break;
case VIDIOCGWIN: /* get window or capture dimensions */
- err = v4l1_compat_get_win_cap_dimensions(arg, inode, file, drv);
+ err = v4l1_compat_get_win_cap_dimensions(arg, file, drv);
break;
case VIDIOCSWIN: /* set window and/or capture dimensions */
- err = v4l1_compat_set_win_cap_dimensions(arg, inode, file, drv);
+ err = v4l1_compat_set_win_cap_dimensions(arg, file, drv);
break;
case VIDIOCCAPTURE: /* turn on/off preview */
- err = v4l1_compat_turn_preview_on_off(arg, inode, file, drv);
+ err = v4l1_compat_turn_preview_on_off(arg, file, drv);
break;
case VIDIOCGCHAN: /* get input information */
- err = v4l1_compat_get_input_info(arg, inode, file, drv);
+ err = v4l1_compat_get_input_info(arg, file, drv);
break;
case VIDIOCSCHAN: /* set input */
- err = v4l1_compat_set_input(arg, inode, file, drv);
+ err = v4l1_compat_set_input(arg, file, drv);
break;
case VIDIOCGPICT: /* get tone controls & partial capture format */
- err = v4l1_compat_get_picture(arg, inode, file, drv);
+ err = v4l1_compat_get_picture(arg, file, drv);
break;
case VIDIOCSPICT: /* set tone controls & partial capture format */
- err = v4l1_compat_set_picture(arg, inode, file, drv);
+ err = v4l1_compat_set_picture(arg, file, drv);
break;
case VIDIOCGTUNER: /* get tuner information */
- err = v4l1_compat_get_tuner(arg, inode, file, drv);
+ err = v4l1_compat_get_tuner(arg, file, drv);
break;
case VIDIOCSTUNER: /* select a tuner input */
- err = v4l1_compat_select_tuner(arg, inode, file, drv);
+ err = v4l1_compat_select_tuner(arg, file, drv);
break;
case VIDIOCGFREQ: /* get frequency */
- err = v4l1_compat_get_frequency(arg, inode, file, drv);
+ err = v4l1_compat_get_frequency(arg, file, drv);
break;
case VIDIOCSFREQ: /* set frequency */
- err = v4l1_compat_set_frequency(arg, inode, file, drv);
+ err = v4l1_compat_set_frequency(arg, file, drv);
break;
case VIDIOCGAUDIO: /* get audio properties/controls */
- err = v4l1_compat_get_audio(arg, inode, file, drv);
+ err = v4l1_compat_get_audio(arg, file, drv);
break;
case VIDIOCSAUDIO: /* set audio controls */
- err = v4l1_compat_set_audio(arg, inode, file, drv);
+ err = v4l1_compat_set_audio(arg, file, drv);
break;
case VIDIOCMCAPTURE: /* capture a frame */
- err = v4l1_compat_capture_frame(arg, inode, file, drv);
+ err = v4l1_compat_capture_frame(arg, file, drv);
break;
case VIDIOCSYNC: /* wait for a frame */
- err = v4l1_compat_sync(arg, inode, file, drv);
+ err = v4l1_compat_sync(arg, file, drv);
break;
case VIDIOCGVBIFMT: /* query VBI data capture format */
- err = v4l1_compat_get_vbi_format(arg, inode, file, drv);
+ err = v4l1_compat_get_vbi_format(arg, file, drv);
break;
case VIDIOCSVBIFMT:
- err = v4l1_compat_set_vbi_format(arg, inode, file, drv);
+ err = v4l1_compat_set_vbi_format(arg, file, drv);
break;
default:
err = -ENOIOCTLCMD;
diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c
index 0e4549922f2..a935bae538e 100644
--- a/drivers/media/video/v4l2-int-device.c
+++ b/drivers/media/video/v4l2-int-device.c
@@ -32,7 +32,7 @@
static DEFINE_MUTEX(mutex);
static LIST_HEAD(int_list);
-static void v4l2_int_device_try_attach_all(void)
+void v4l2_int_device_try_attach_all(void)
{
struct v4l2_int_device *m, *s;
@@ -66,6 +66,7 @@ static void v4l2_int_device_try_attach_all(void)
}
}
}
+EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all);
static int ioctl_sort_cmp(const void *a, const void *b)
{
@@ -144,6 +145,7 @@ int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd)
find_ioctl(d->u.slave, cmd,
(v4l2_int_ioctl_func *)no_such_ioctl_0))(d);
}
+EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0);
static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg)
{
@@ -156,5 +158,6 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg)
find_ioctl(d->u.slave, cmd,
(v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg);
}
+EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1);
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 155c9d77a46..710e1a40c42 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -625,13 +625,13 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
return -EINVAL;
}
-static int __video_do_ioctl(struct inode *inode, struct file *file,
+static int __video_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
struct video_device *vfd = video_devdata(file);
const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
- void *fh = file->private_data;
- int ret = -EINVAL;
+ void *fh = file->private_data;
+ int ret = -EINVAL;
if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
@@ -675,7 +675,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
V4L2 ioctls.
********************************************************/
if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)
- return v4l_compat_translate_ioctl(inode, file, cmd, arg,
+ return v4l_compat_translate_ioctl(file, cmd, arg,
__video_do_ioctl);
#endif
@@ -1768,7 +1768,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
return ret;
}
-int video_ioctl2(struct inode *inode, struct file *file,
+int __video_ioctl2(struct file *file,
unsigned int cmd, unsigned long arg)
{
char sbuf[128];
@@ -1832,7 +1832,7 @@ int video_ioctl2(struct inode *inode, struct file *file,
}
/* Handles IOCTL */
- err = __video_do_ioctl(inode, file, cmd, parg);
+ err = __video_do_ioctl(file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
if (is_ext_ctrl) {
@@ -1860,4 +1860,11 @@ out:
kfree(mbuf);
return err;
}
+EXPORT_SYMBOL(__video_ioctl2);
+
+int video_ioctl2(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return __video_ioctl2(file, cmd, arg);
+}
EXPORT_SYMBOL(video_ioctl2);
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index b56cffcbfd4..0e7dcba8e4a 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -126,7 +126,6 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
mutex_lock(&dvb->lock);
dvb->nfeeds--;
if (0 == dvb->nfeeds && NULL != dvb->thread) {
- // FIXME: cx8802_cancel_buffers(dev);
err = kthread_stop(dvb->thread);
dvb->thread = NULL;
}
@@ -134,30 +133,38 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
return err;
}
-/* ------------------------------------------------------------------ */
-
-int videobuf_dvb_register(struct videobuf_dvb *dvb,
+static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
struct module *module,
void *adapter_priv,
struct device *device,
- short *adapter_nr)
+ char *adapter_name,
+ short *adapter_nr,
+ int mfe_shared)
{
int result;
- mutex_init(&dvb->lock);
+ mutex_init(&fe->lock);
/* register adapter */
- result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device,
- adapter_nr);
+ result = dvb_register_adapter(&fe->adapter, adapter_name, module,
+ device, adapter_nr);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
- dvb->name, result);
- goto fail_adapter;
+ adapter_name, result);
}
- dvb->adapter.priv = adapter_priv;
+ fe->adapter.priv = adapter_priv;
+ fe->adapter.mfe_shared = mfe_shared;
+
+ return result;
+}
+
+static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter,
+ struct videobuf_dvb *dvb)
+{
+ int result;
/* register frontend */
- result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ result = dvb_register_frontend(adapter, dvb->frontend);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
dvb->name, result);
@@ -183,7 +190,8 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
dvb->dmxdev.filternum = 256;
dvb->dmxdev.demux = &dvb->demux.dmx;
dvb->dmxdev.capabilities = 0;
- result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+ result = dvb_dmxdev_init(&dvb->dmxdev, adapter);
+
if (result < 0) {
printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
dvb->name, result);
@@ -214,7 +222,11 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
}
/* register network adapter */
- dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+ dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
+ if (dvb->net.dvbdev == NULL) {
+ result = -ENOMEM;
+ goto fail_fe_conn;
+ }
return 0;
fail_fe_conn:
@@ -229,30 +241,157 @@ fail_dmx:
dvb_unregister_frontend(dvb->frontend);
fail_frontend:
dvb_frontend_detach(dvb->frontend);
- dvb_unregister_adapter(&dvb->adapter);
-fail_adapter:
+ dvb->frontend = NULL;
+
return result;
}
-void videobuf_dvb_unregister(struct videobuf_dvb *dvb)
+/* ------------------------------------------------------------------ */
+/* Register a single adapter and one or more frontends */
+int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
+ struct module *module,
+ void *adapter_priv,
+ struct device *device,
+ short *adapter_nr,
+ int mfe_shared)
{
- dvb_net_release(&dvb->net);
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
- dvb_dmxdev_release(&dvb->dmxdev);
- dvb_dmx_release(&dvb->demux);
- dvb_unregister_frontend(dvb->frontend);
- dvb_frontend_detach(dvb->frontend);
- dvb_unregister_adapter(&dvb->adapter);
+ struct list_head *list, *q;
+ struct videobuf_dvb_frontend *fe;
+ int res;
+
+ fe = videobuf_dvb_get_frontend(f, 1);
+ if (!fe) {
+ printk(KERN_WARNING "Unable to register the adapter which has no frontends\n");
+ return -EINVAL;
+ }
+
+ /* Bring up the adapter */
+ res = videobuf_dvb_register_adapter(f, module, adapter_priv, device,
+ fe->dvb.name, adapter_nr, mfe_shared);
+ if (res < 0) {
+ printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res);
+ return res;
+ }
+
+ /* Attach all of the frontends to the adapter */
+ mutex_lock(&f->lock);
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+ res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb);
+ if (res < 0) {
+ printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n",
+ fe->dvb.name, res);
+ goto err;
+ }
+ }
+ mutex_unlock(&f->lock);
+ return 0;
+
+err:
+ mutex_unlock(&f->lock);
+ videobuf_dvb_unregister_bus(f);
+ return res;
+}
+EXPORT_SYMBOL(videobuf_dvb_register_bus);
+
+void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f)
+{
+ videobuf_dvb_dealloc_frontends(f);
+
+ dvb_unregister_adapter(&f->adapter);
}
+EXPORT_SYMBOL(videobuf_dvb_unregister_bus);
-EXPORT_SYMBOL(videobuf_dvb_register);
-EXPORT_SYMBOL(videobuf_dvb_unregister);
+struct videobuf_dvb_frontend *videobuf_dvb_get_frontend(
+ struct videobuf_dvb_frontends *f, int id)
+{
+ struct list_head *list, *q;
+ struct videobuf_dvb_frontend *fe, *ret = NULL;
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * compile-command: "make DVB=1"
- * End:
- */
+ mutex_lock(&f->lock);
+
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+ if (fe->id == id) {
+ ret = fe;
+ break;
+ }
+ }
+
+ mutex_unlock(&f->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(videobuf_dvb_get_frontend);
+
+int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f,
+ struct dvb_frontend *p)
+{
+ struct list_head *list, *q;
+ struct videobuf_dvb_frontend *fe = NULL;
+ int ret = 0;
+
+ mutex_lock(&f->lock);
+
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+ if (fe->dvb.frontend == p) {
+ ret = fe->id;
+ break;
+ }
+ }
+
+ mutex_unlock(&f->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(videobuf_dvb_find_frontend);
+
+struct videobuf_dvb_frontend *videobuf_dvb_alloc_frontend(
+ struct videobuf_dvb_frontends *f, int id)
+{
+ struct videobuf_dvb_frontend *fe;
+
+ fe = kzalloc(sizeof(struct videobuf_dvb_frontend), GFP_KERNEL);
+ if (fe == NULL)
+ goto fail_alloc;
+
+ fe->id = id;
+ mutex_init(&fe->dvb.lock);
+
+ mutex_lock(&f->lock);
+ list_add_tail(&fe->felist, &f->felist);
+ mutex_unlock(&f->lock);
+
+fail_alloc:
+ return fe;
+}
+EXPORT_SYMBOL(videobuf_dvb_alloc_frontend);
+
+void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f)
+{
+ struct list_head *list, *q;
+ struct videobuf_dvb_frontend *fe;
+
+ mutex_lock(&f->lock);
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+ if (fe->dvb.net.dvbdev) {
+ dvb_net_release(&fe->dvb.net);
+ fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
+ &fe->dvb.fe_mem);
+ fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
+ &fe->dvb.fe_hw);
+ dvb_dmxdev_release(&fe->dvb.dmxdev);
+ dvb_dmx_release(&fe->dvb.demux);
+ dvb_unregister_frontend(fe->dvb.frontend);
+ }
+ if (fe->dvb.frontend)
+ /* always allocated, may have been reset */
+ dvb_frontend_detach(fe->dvb.frontend);
+ list_del(list); /* remove list entry */
+ kfree(fe); /* free frontend allocation */
+ }
+ mutex_unlock(&f->lock);
+}
+EXPORT_SYMBOL(videobuf_dvb_dealloc_frontends);
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 65c8af18e76..e15e48f04be 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -128,12 +128,56 @@ struct vivi_fmt {
int depth;
};
-static struct vivi_fmt format = {
- .name = "4:2:2, packed, YUYV",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
+static struct vivi_fmt formats[] = {
+ {
+ .name = "4:2:2, packed, YUYV",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ },
+ {
+ .name = "4:2:2, packed, UYVY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ },
+ {
+ .name = "RGB565 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+ .depth = 16,
+ },
+ {
+ .name = "RGB565 (BE)",
+ .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+ .depth = 16,
+ },
+ {
+ .name = "RGB555 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+ .depth = 16,
+ },
+ {
+ .name = "RGB555 (BE)",
+ .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+ .depth = 16,
+ },
};
+static struct vivi_fmt *get_format(struct v4l2_format *f)
+{
+ struct vivi_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+ fmt = &formats[k];
+ if (fmt->fourcc == f->fmt.pix.pixelformat)
+ break;
+ }
+
+ if (k == ARRAY_SIZE(formats))
+ return NULL;
+
+ return &formats[k];
+}
+
struct sg_to_addr {
int pos;
struct scatterlist *sg;
@@ -190,6 +234,7 @@ struct vivi_fh {
struct videobuf_queue vb_vidq;
enum v4l2_buf_type type;
+ unsigned char bars[8][3];
};
/* ------------------------------------------------------------------
@@ -234,42 +279,118 @@ static u8 bars[8][3] = {
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
-static void gen_line(char *basep, int inipos, int wmax,
- int hmax, int line, int count, char *timestr)
+static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
{
- int w, i, j, y;
- int pos = inipos;
- char *p, *s;
- u8 chr, r, g, b, color;
+ unsigned char r_y, g_u, b_v;
+ unsigned char *p;
+ int color;
- /* We will just duplicate the second pixel at the packet */
- wmax /= 2;
+ r_y = fh->bars[colorpos][0]; /* R or precalculated Y */
+ g_u = fh->bars[colorpos][1]; /* G or precalculated U */
+ b_v = fh->bars[colorpos][2]; /* B or precalculated V */
- /* Generate a standard color bar pattern */
- for (w = 0; w < wmax; w++) {
- int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
- r = bars[colorpos][0];
- g = bars[colorpos][1];
- b = bars[colorpos][2];
-
- for (color = 0; color < 4; color++) {
- p = basep + pos;
+ for (color = 0; color < 4; color++) {
+ p = buf + color;
+ switch (fh->fmt->fourcc) {
+ case V4L2_PIX_FMT_YUYV:
switch (color) {
case 0:
case 2:
- *p = TO_Y(r, g, b); /* Luma */
+ *p = r_y;
break;
case 1:
- *p = TO_U(r, g, b); /* Cb */
+ *p = g_u;
break;
case 3:
- *p = TO_V(r, g, b); /* Cr */
+ *p = b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ switch (color) {
+ case 1:
+ case 3:
+ *p = r_y;
+ break;
+ case 0:
+ *p = g_u;
+ break;
+ case 2:
+ *p = b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ switch (color) {
+ case 0:
+ case 2:
+ *p = (g_u << 5) | b_v;
+ break;
+ case 1:
+ case 3:
+ *p = (r_y << 3) | (g_u >> 3);
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB565X:
+ switch (color) {
+ case 0:
+ case 2:
+ *p = (r_y << 3) | (g_u >> 3);
+ break;
+ case 1:
+ case 3:
+ *p = (g_u << 5) | b_v;
break;
}
- pos++;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ switch (color) {
+ case 0:
+ case 2:
+ *p = (g_u << 5) | b_v;
+ break;
+ case 1:
+ case 3:
+ *p = (r_y << 2) | (g_u >> 3);
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB555X:
+ switch (color) {
+ case 0:
+ case 2:
+ *p = (r_y << 2) | (g_u >> 3);
+ break;
+ case 1:
+ case 3:
+ *p = (g_u << 5) | b_v;
+ break;
+ }
+ break;
}
}
+}
+
+static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
+ int hmax, int line, int count, char *timestr)
+{
+ int w, i, j;
+ int pos = inipos;
+ char *s;
+ u8 chr;
+
+ /* We will just duplicate the second pixel at the packet */
+ wmax /= 2;
+
+ /* Generate a standard color bar pattern */
+ for (w = 0; w < wmax; w++) {
+ int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
+
+ gen_twopix(fh, basep + pos, colorpos);
+ pos += 4; /* only 16 bpp supported for now */
+ }
/* Checks if it is possible to show timestamp */
if (TSTAMP_MAX_Y >= hmax)
@@ -283,38 +404,12 @@ static void gen_line(char *basep, int inipos, int wmax,
for (s = timestr; *s; s++) {
chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
for (i = 0; i < 7; i++) {
- if (chr & 1 << (7 - i)) {
- /* Font color*/
- r = 0;
- g = 198;
- b = 0;
- } else {
- /* Background color */
- r = bars[BLACK][0];
- g = bars[BLACK][1];
- b = bars[BLACK][2];
- }
-
pos = inipos + j * 2;
- for (color = 0; color < 4; color++) {
- p = basep + pos;
-
- y = TO_Y(r, g, b);
-
- switch (color) {
- case 0:
- case 2:
- *p = TO_Y(r, g, b); /* Luma */
- break;
- case 1:
- *p = TO_U(r, g, b); /* Cb */
- break;
- case 3:
- *p = TO_V(r, g, b); /* Cr */
- break;
- }
- pos++;
- }
+ /* Draw white font on black background */
+ if (chr & 1 << (7 - i))
+ gen_twopix(fh, basep + pos, WHITE);
+ else
+ gen_twopix(fh, basep + pos, BLACK);
j++;
}
}
@@ -324,8 +419,9 @@ end:
return;
}
-static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
+static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
{
+ struct vivi_dev *dev = fh->dev;
int h , pos = 0;
int hmax = buf->vb.height;
int wmax = buf->vb.width;
@@ -341,7 +437,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
return;
for (h = 0; h < hmax; h++) {
- gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+ gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
dev->timestr);
memcpy(vbuf + pos, tmpbuf, wmax * 2);
pos += wmax*2;
@@ -410,7 +506,7 @@ static void vivi_thread_tick(struct vivi_fh *fh)
do_gettimeofday(&buf->vb.ts);
/* Fill buffer */
- vivi_fillbuff(dev, buf);
+ vivi_fillbuff(fh, buf);
dprintk(dev, 1, "filled buffer %p\n", buf);
wake_up(&buf->vb.done);
@@ -636,11 +732,15 @@ static int vidioc_querycap(struct file *file, void *priv,
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- if (f->index > 0)
+ struct vivi_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(formats))
return -EINVAL;
- strlcpy(f->description, format.name, sizeof(f->description));
- f->pixelformat = format.fourcc;
+ fmt = &formats[f->index];
+
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
return 0;
}
@@ -670,13 +770,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
enum v4l2_field field;
unsigned int maxw, maxh;
- if (format.fourcc != f->fmt.pix.pixelformat) {
- dprintk(dev, 1, "Fourcc format (0x%08x) invalid. "
- "Driver accepts only 0x%08x\n",
- f->fmt.pix.pixelformat, format.fourcc);
+ fmt = get_format(f);
+ if (!fmt) {
+ dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
return -EINVAL;
}
- fmt = &format;
field = f->fmt.pix.field;
@@ -714,6 +813,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
{
struct vivi_fh *fh = priv;
struct videobuf_queue *q = &fh->vb_vidq;
+ unsigned char r, g, b;
+ int k, is_yuv;
int ret = vidioc_try_fmt_vid_cap(file, fh, f);
if (ret < 0)
@@ -727,12 +828,49 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
goto out;
}
- fh->fmt = &format;
+ fh->fmt = get_format(f);
fh->width = f->fmt.pix.width;
fh->height = f->fmt.pix.height;
fh->vb_vidq.field = f->fmt.pix.field;
fh->type = f->type;
+ /* precalculate color bar values to speed up rendering */
+ for (k = 0; k < 8; k++) {
+ r = bars[k][0];
+ g = bars[k][1];
+ b = bars[k][2];
+ is_yuv = 0;
+
+ switch (fh->fmt->fourcc) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ is_yuv = 1;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB565X:
+ r >>= 3;
+ g >>= 2;
+ b >>= 3;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ case V4L2_PIX_FMT_RGB555X:
+ r >>= 3;
+ g >>= 3;
+ b >>= 3;
+ break;
+ }
+
+ if (is_yuv) {
+ fh->bars[k][0] = TO_Y(r, g, b); /* Luma */
+ fh->bars[k][1] = TO_U(r, g, b); /* Cb */
+ fh->bars[k][2] = TO_V(r, g, b); /* Cr */
+ } else {
+ fh->bars[k][0] = r;
+ fh->bars[k][1] = g;
+ fh->bars[k][2] = b;
+ }
+ }
+
ret = 0;
out:
mutex_unlock(&q->vb_lock);
@@ -886,8 +1024,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
File operations for the device
------------------------------------------------------------------*/
-#define line_buf_size(norm) (norm_maxw(norm)*(format.depth+7)/8)
-
static int vivi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
@@ -936,7 +1072,7 @@ unlock:
fh->dev = dev;
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fh->fmt = &format;
+ fh->fmt = &formats[0];
fh->width = 640;
fh->height = 480;
@@ -1027,11 +1163,11 @@ static int vivi_release(void)
if (-1 != dev->vfd->minor) {
printk(KERN_INFO "%s: unregistering /dev/video%d\n",
- VIVI_MODULE_NAME, dev->vfd->minor);
+ VIVI_MODULE_NAME, dev->vfd->num);
video_unregister_device(dev->vfd);
} else {
printk(KERN_INFO "%s: releasing /dev/video%d\n",
- VIVI_MODULE_NAME, dev->vfd->minor);
+ VIVI_MODULE_NAME, dev->vfd->num);
video_device_release(dev->vfd);
}
@@ -1171,7 +1307,7 @@ static int __init vivi_init(void)
dev->vfd = vfd;
printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
- VIVI_MODULE_NAME, vfd->minor);
+ VIVI_MODULE_NAME, vfd->num);
}
if (ret < 0) {
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 45be9ec8edc..67aa0db4b81 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -22,32 +22,21 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/types.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
#include <asm/uaccess.h>
-
#include <linux/i2c.h>
-
-#define I2C_NAME(x) (x)->name
-
-#include <linux/videodev.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev.h>
#include <linux/video_decoder.h>
-#define I2C_VPX3220 0x86
-#define VPX3220_DEBUG KERN_DEBUG "vpx3220: "
+MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
+MODULE_AUTHOR("Laurent Pinchart");
+MODULE_LICENSE("GPL");
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
#define VPX_TIMEOUT_COUNT 10
/* ----------------------------------------------------------------------- */
@@ -67,10 +56,8 @@ struct vpx3220 {
static char *inputs[] = { "internal", "composite", "svideo" };
/* ----------------------------------------------------------------------- */
-static inline int
-vpx3220_write (struct i2c_client *client,
- u8 reg,
- u8 value)
+
+static inline int vpx3220_write(struct i2c_client *client, u8 reg, u8 value)
{
struct vpx3220 *decoder = i2c_get_clientdata(client);
@@ -78,15 +65,12 @@ vpx3220_write (struct i2c_client *client,
return i2c_smbus_write_byte_data(client, reg, value);
}
-static inline int
-vpx3220_read (struct i2c_client *client,
- u8 reg)
+static inline int vpx3220_read(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
-static int
-vpx3220_fp_status (struct i2c_client *client)
+static int vpx3220_fp_status(struct i2c_client *client)
{
unsigned char status;
unsigned int i;
@@ -106,14 +90,11 @@ vpx3220_fp_status (struct i2c_client *client)
return -1;
}
-static int
-vpx3220_fp_write (struct i2c_client *client,
- u8 fpaddr,
- u16 data)
+static int vpx3220_fp_write(struct i2c_client *client, u8 fpaddr, u16 data)
{
/* Write the 16-bit address to the FPWR register */
if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
- dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+ v4l_dbg(1, debug, client, "%s: failed\n", __func__);
return -1;
}
@@ -122,22 +103,20 @@ vpx3220_fp_write (struct i2c_client *client,
/* Write the 16-bit data to the FPDAT register */
if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
- dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+ v4l_dbg(1, debug, client, "%s: failed\n", __func__);
return -1;
}
return 0;
}
-static u16
-vpx3220_fp_read (struct i2c_client *client,
- u16 fpaddr)
+static u16 vpx3220_fp_read(struct i2c_client *client, u16 fpaddr)
{
s16 data;
/* Write the 16-bit address to the FPRD register */
if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
- dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+ v4l_dbg(1, debug, client, "%s: failed\n", __func__);
return -1;
}
@@ -147,25 +126,22 @@ vpx3220_fp_read (struct i2c_client *client,
/* Read the 16-bit data from the FPDAT register */
data = i2c_smbus_read_word_data(client, 0x28);
if (data == -1) {
- dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+ v4l_dbg(1, debug, client, "%s: failed\n", __func__);
return -1;
}
return swab16(data);
}
-static int
-vpx3220_write_block (struct i2c_client *client,
- const u8 *data,
- unsigned int len)
+static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
{
u8 reg;
int ret = -1;
while (len >= 2) {
reg = *data++;
- if ((ret =
- vpx3220_write(client, reg, *data++)) < 0)
+ ret = vpx3220_write(client, reg, *data++);
+ if (ret < 0)
break;
len -= 2;
}
@@ -173,10 +149,8 @@ vpx3220_write_block (struct i2c_client *client,
return ret;
}
-static int
-vpx3220_write_fp_block (struct i2c_client *client,
- const u16 *data,
- unsigned int len)
+static int vpx3220_write_fp_block(struct i2c_client *client,
+ const u16 *data, unsigned int len)
{
u8 reg;
int ret = 0;
@@ -285,25 +259,20 @@ static const unsigned short init_fp[] = {
0x4b, 0x298, /* PLL gain */
};
-static void
-vpx3220_dump_i2c (struct i2c_client *client)
+static void vpx3220_dump_i2c(struct i2c_client *client)
{
int len = sizeof(init_common);
const unsigned char *data = init_common;
while (len > 1) {
- dprintk(1,
- KERN_DEBUG "vpx3216b i2c reg 0x%02x data 0x%02x\n",
+ v4l_dbg(1, debug, client, "i2c reg 0x%02x data 0x%02x\n",
*data, vpx3220_read(client, *data));
data += 2;
len -= 2;
}
}
-static int
-vpx3220_command (struct i2c_client *client,
- unsigned int cmd,
- void *arg)
+static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg)
{
struct vpx3220 *decoder = i2c_get_clientdata(client);
@@ -315,7 +284,6 @@ vpx3220_command (struct i2c_client *client,
vpx3220_write_fp_block(client, init_fp,
sizeof(init_fp) >> 1);
switch (decoder->norm) {
-
case VIDEO_MODE_NTSC:
vpx3220_write_fp_block(client, init_ntsc,
sizeof(init_ntsc) >> 1);
@@ -334,21 +302,20 @@ vpx3220_command (struct i2c_client *client,
sizeof(init_pal) >> 1);
break;
}
- }
break;
+ }
case DECODER_DUMP:
{
vpx3220_dump_i2c(client);
- }
break;
+ }
case DECODER_GET_CAPABILITIES:
{
struct video_decoder_capability *cap = arg;
- dprintk(1, KERN_DEBUG "%s: DECODER_GET_CAPABILITIES\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "DECODER_GET_CAPABILITIES\n");
cap->flags = VIDEO_DECODER_PAL |
VIDEO_DECODER_NTSC |
@@ -357,20 +324,18 @@ vpx3220_command (struct i2c_client *client,
VIDEO_DECODER_CCIR;
cap->inputs = 3;
cap->outputs = 1;
- }
break;
+ }
case DECODER_GET_STATUS:
{
int res = 0, status;
- dprintk(1, KERN_INFO "%s: DECODER_GET_STATUS\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "DECODER_GET_STATUS\n");
status = vpx3220_fp_read(client, 0x0f3);
- dprintk(1, KERN_INFO "%s: status: 0x%04x\n", I2C_NAME(client),
- status);
+ v4l_dbg(1, debug, client, "status: 0x%04x\n", status);
if (status < 0)
return status;
@@ -379,7 +344,6 @@ vpx3220_command (struct i2c_client *client,
res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR;
switch (status & 0x18) {
-
case 0x00:
case 0x10:
case 0x14:
@@ -400,8 +364,8 @@ vpx3220_command (struct i2c_client *client,
}
*(int *) arg = res;
- }
break;
+ }
case DECODER_SET_NORM:
{
@@ -413,50 +377,43 @@ vpx3220_command (struct i2c_client *client,
choosen video norm */
temp_input = vpx3220_fp_read(client, 0xf2);
- dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n",
- I2C_NAME(client), *iarg);
+ v4l_dbg(1, debug, client, "DECODER_SET_NORM %d\n", *iarg);
switch (*iarg) {
-
case VIDEO_MODE_NTSC:
vpx3220_write_fp_block(client, init_ntsc,
sizeof(init_ntsc) >> 1);
- dprintk(1, KERN_INFO "%s: norm switched to NTSC\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "norm switched to NTSC\n");
break;
case VIDEO_MODE_PAL:
vpx3220_write_fp_block(client, init_pal,
sizeof(init_pal) >> 1);
- dprintk(1, KERN_INFO "%s: norm switched to PAL\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "norm switched to PAL\n");
break;
case VIDEO_MODE_SECAM:
vpx3220_write_fp_block(client, init_secam,
sizeof(init_secam) >> 1);
- dprintk(1, KERN_INFO "%s: norm switched to SECAM\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "norm switched to SECAM\n");
break;
case VIDEO_MODE_AUTO:
/* FIXME This is only preliminary support */
data = vpx3220_fp_read(client, 0xf2) & 0x20;
vpx3220_fp_write(client, 0xf2, 0x00c0 | data);
- dprintk(1, KERN_INFO "%s: norm switched to Auto\n",
- I2C_NAME(client));
+ v4l_dbg(1, debug, client, "norm switched to AUTO\n");
break;
default:
return -EINVAL;
-
}
decoder->norm = *iarg;
/* And here we set the backed up video input again */
vpx3220_fp_write(client, 0xf2, temp_input | 0x0010);
udelay(10);
- }
break;
+ }
case DECODER_SET_INPUT:
{
@@ -475,8 +432,7 @@ vpx3220_command (struct i2c_client *client,
if (*iarg < 0 || *iarg > 2)
return -EINVAL;
- dprintk(1, KERN_INFO "%s: input switched to %s\n",
- I2C_NAME(client), inputs[*iarg]);
+ v4l_dbg(1, debug, client, "input switched to %s\n", inputs[*iarg]);
vpx3220_write(client, 0x33, input[*iarg][0]);
@@ -488,8 +444,8 @@ vpx3220_command (struct i2c_client *client,
data | (input[*iarg][1] << 5) | 0x0010);
udelay(10);
- }
break;
+ }
case DECODER_SET_OUTPUT:
{
@@ -499,19 +455,18 @@ vpx3220_command (struct i2c_client *client,
if (*iarg != 0) {
return -EINVAL;
}
- }
break;
+ }
case DECODER_ENABLE_OUTPUT:
{
int *iarg = arg;
- dprintk(1, KERN_DEBUG "%s: DECODER_ENABLE_OUTPUT %d\n",
- I2C_NAME(client), *iarg);
+ v4l_dbg(1, debug, client, "DECODER_ENABLE_OUTPUT %d\n", *iarg);
vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00));
- }
break;
+ }
case DECODER_SET_PICTURE:
{
@@ -542,8 +497,8 @@ vpx3220_command (struct i2c_client *client,
vpx3220_fp_write(client, 0x1c,
((decoder->hue - 32768) >> 6) & 0xFFF);
}
- }
break;
+ }
default:
return -EINVAL;
@@ -552,8 +507,7 @@ vpx3220_command (struct i2c_client *client,
return 0;
}
-static int
-vpx3220_init_client (struct i2c_client *client)
+static int vpx3220_init_client(struct i2c_client *client)
{
vpx3220_write_block(client, init_common, sizeof(init_common));
vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1);
@@ -567,115 +521,26 @@ vpx3220_init_client (struct i2c_client *client)
* Client management code
*/
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] =
- { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4,
- I2C_CLIENT_END
-};
-
-static unsigned short ignore = I2C_CLIENT_END;
+static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .probe = &ignore,
- .ignore = &ignore,
-};
-
-static struct i2c_driver vpx3220_i2c_driver;
-
-static int
-vpx3220_detach_client (struct i2c_client *client)
-{
- struct vpx3220 *decoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
-
- kfree(decoder);
- kfree(client);
-
- return 0;
-}
+I2C_CLIENT_INSMOD;
-static int
-vpx3220_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
+static int vpx3220_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int err;
- struct i2c_client *client;
struct vpx3220 *decoder;
-
- dprintk(1, VPX3220_DEBUG "%s\n", __func__);
+ const char *name = NULL;
+ u8 ver;
+ u16 pn;
/* Check if the adapter supports the needed features */
- if (!i2c_check_functionality
- (adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
- return 0;
-
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == NULL) {
- return -ENOMEM;
- }
-
- client->addr = address;
- client->adapter = adapter;
- client->driver = &vpx3220_i2c_driver;
-
- /* Check for manufacture ID and part number */
- if (kind < 0) {
- u8 id;
- u16 pn;
-
- id = vpx3220_read(client, 0x00);
- if (id != 0xec) {
- dprintk(1,
- KERN_INFO
- "vpx3220_attach: Wrong manufacturer ID (0x%02x)\n",
- id);
- kfree(client);
- return 0;
- }
-
- pn = (vpx3220_read(client, 0x02) << 8) +
- vpx3220_read(client, 0x01);
- switch (pn) {
- case 0x4680:
- strlcpy(I2C_NAME(client), "vpx3220a",
- sizeof(I2C_NAME(client)));
- break;
- case 0x4260:
- strlcpy(I2C_NAME(client), "vpx3216b",
- sizeof(I2C_NAME(client)));
- break;
- case 0x4280:
- strlcpy(I2C_NAME(client), "vpx3214c",
- sizeof(I2C_NAME(client)));
- break;
- default:
- dprintk(1,
- KERN_INFO
- "%s: Wrong part number (0x%04x)\n",
- __func__, pn);
- kfree(client);
- return 0;
- }
- } else {
- strlcpy(I2C_NAME(client), "forced vpx32xx",
- sizeof(I2C_NAME(client)));
- }
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
- if (decoder == NULL) {
- kfree(client);
+ if (decoder == NULL)
return -ENOMEM;
- }
decoder->norm = VIDEO_MODE_PAL;
decoder->input = 0;
decoder->enable = 1;
@@ -685,63 +550,52 @@ vpx3220_detect_client (struct i2c_adapter *adapter,
decoder->sat = 32768;
i2c_set_clientdata(client, decoder);
- err = i2c_attach_client(client);
- if (err) {
- kfree(client);
- kfree(decoder);
- return err;
+ ver = i2c_smbus_read_byte_data(client, 0x00);
+ pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
+ i2c_smbus_read_byte_data(client, 0x01);
+ if (ver == 0xec) {
+ switch (pn) {
+ case 0x4680:
+ name = "vpx3220a";
+ break;
+ case 0x4260:
+ name = "vpx3216b";
+ break;
+ case 0x4280:
+ name = "vpx3214c";
+ break;
+ }
}
-
- dprintk(1, KERN_INFO "%s: vpx32xx client found at address 0x%02x\n",
- I2C_NAME(client), client->addr << 1);
+ if (name)
+ v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+ client->addr << 1, client->adapter->name);
+ else
+ v4l_info(client, "chip (%02x:%04x) found @ 0x%x (%s)\n",
+ ver, pn, client->addr << 1, client->adapter->name);
vpx3220_init_client(client);
-
return 0;
}
-static int
-vpx3220_attach_adapter (struct i2c_adapter *adapter)
+static int vpx3220_remove(struct i2c_client *client)
{
- int ret;
-
- ret = i2c_probe(adapter, &addr_data, &vpx3220_detect_client);
- dprintk(1, VPX3220_DEBUG "%s: i2c_probe returned %d\n",
- __func__, ret);
- return ret;
+ kfree(i2c_get_clientdata(client));
+ return 0;
}
-/* -----------------------------------------------------------------------
- * Driver initialization and cleanup code
- */
-
-static struct i2c_driver vpx3220_i2c_driver = {
- .driver = {
- .name = "vpx3220",
- },
-
- .id = I2C_DRIVERID_VPX3220,
+static const struct i2c_device_id vpx3220_id[] = {
+ { "vpx3220a", 0 },
+ { "vpx3216b", 0 },
+ { "vpx3214c", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vpx3220_id);
- .attach_adapter = vpx3220_attach_adapter,
- .detach_client = vpx3220_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "vpx3220",
+ .driverid = I2C_DRIVERID_VPX3220,
.command = vpx3220_command,
+ .probe = vpx3220_probe,
+ .remove = vpx3220_remove,
+ .id_table = vpx3220_id,
};
-
-static int __init
-vpx3220_init (void)
-{
- return i2c_add_driver(&vpx3220_i2c_driver);
-}
-
-static void __exit
-vpx3220_cleanup (void)
-{
- i2c_del_driver(&vpx3220_i2c_driver);
-}
-
-module_init(vpx3220_init);
-module_exit(vpx3220_cleanup);
-
-MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
-MODULE_AUTHOR("Laurent Pinchart");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index dcd45dbd82d..4dfb43bd184 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -2398,7 +2398,7 @@ error:
cam->sensor = CC_UNKNOWN;
DBG(1, "Image sensor initialization failed for %s (/dev/video%d). "
"Try to detach and attach this device again",
- symbolic(camlist, cam->id), cam->v4ldev->minor)
+ symbolic(camlist, cam->id), cam->v4ldev->num)
return err;
}
@@ -2644,7 +2644,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
{
mutex_lock(&w9968cf_devlist_mutex);
- DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor)
+ DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->num)
video_unregister_device(cam->v4ldev);
list_del(&cam->v4llist);
@@ -2679,7 +2679,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
DBG(2, "No supported image sensor has been detected by the "
"'ovcamchip' module for the %s (/dev/video%d). Make "
"sure it is loaded *before* (re)connecting the camera.",
- symbolic(camlist, cam->id), cam->v4ldev->minor)
+ symbolic(camlist, cam->id), cam->v4ldev->num)
mutex_unlock(&cam->dev_mutex);
up_read(&w9968cf_disconnect);
return -ENODEV;
@@ -2687,7 +2687,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
if (cam->users) {
DBG(2, "%s (/dev/video%d) has been already occupied by '%s'",
- symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command)
+ symbolic(camlist, cam->id), cam->v4ldev->num, cam->command)
if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
mutex_unlock(&cam->dev_mutex);
up_read(&w9968cf_disconnect);
@@ -2709,7 +2709,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
}
DBG(5, "Opening '%s', /dev/video%d ...",
- symbolic(camlist, cam->id), cam->v4ldev->minor)
+ symbolic(camlist, cam->id), cam->v4ldev->num)
cam->streaming = 0;
cam->misconfigured = 0;
@@ -2947,7 +2947,7 @@ static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
.minheight = cam->minheight,
};
sprintf(cap.name, "W996[87]CF USB Camera #%d",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
cap.maxwidth = (cam->upscaling && w9968cf_vpp)
? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
: cam->maxwidth;
@@ -3567,7 +3567,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor)
+ DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->num)
/* Set some basic constants */
w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
@@ -3618,7 +3618,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
DBG(2, "The device is open (/dev/video%d)! "
"Process name: %s. Deregistration and memory "
"deallocation are deferred on close.",
- cam->v4ldev->minor, cam->command)
+ cam->v4ldev->num, cam->command)
cam->misconfigured = 1;
w9968cf_stop_transfer(cam);
wake_up_interruptible(&cam->wait_queue);
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 6a0902bcba6..9fc58170763 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -539,7 +539,7 @@ static int zc0301_stream_interrupt(struct zc0301_device* cam)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "URB timeout reached. The camera is misconfigured. To "
"use it, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -EIO;
}
@@ -640,7 +640,7 @@ static void zc0301_release_resources(struct kref *kref)
{
struct zc0301_device *cam = container_of(kref, struct zc0301_device,
kref);
- DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+ DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
usb_put_dev(cam->usbdev);
@@ -679,7 +679,7 @@ static int zc0301_open(struct inode* inode, struct file* filp)
}
if (cam->users) {
- DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->num);
DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
@@ -722,7 +722,7 @@ static int zc0301_open(struct inode* inode, struct file* filp)
cam->frame_count = 0;
zc0301_empty_framequeues(cam);
- DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+ DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num);
out:
mutex_unlock(&cam->open_mutex);
@@ -746,7 +746,7 @@ static int zc0301_release(struct inode* inode, struct file* filp)
cam->users--;
wake_up_interruptible_nr(&cam->wait_open, 1);
- DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+ DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num);
kref_put(&cam->kref, zc0301_release_resources);
@@ -1275,7 +1275,7 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -EIO;
}
@@ -1288,7 +1288,7 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -ENOMEM;
}
@@ -1470,7 +1470,7 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -EIO;
}
@@ -1482,7 +1482,7 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
"use the camera, close and open /dev/video%d again.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
return -ENOMEM;
}
@@ -1529,7 +1529,7 @@ zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
"problems. To use the camera, close and open "
- "/dev/video%d again.", cam->v4ldev->minor);
+ "/dev/video%d again.", cam->v4ldev->num);
return -EIO;
}
@@ -2005,7 +2005,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+ DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num);
cam->module_param.force_munmap = force_munmap[dev_nr];
cam->module_param.frame_timeout = frame_timeout[dev_nr];
@@ -2044,7 +2044,7 @@ static void zc0301_usb_disconnect(struct usb_interface* intf)
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
"memory deallocation are deferred.",
- cam->v4ldev->minor);
+ cam->v4ldev->num);
cam->state |= DEV_MISCONFIGURED;
zc0301_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index 3282be73029..fa5f2f8f518 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -817,6 +817,7 @@ zoran_register_i2c (struct zoran *zr)
memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
sizeof(struct i2c_algo_bit_data));
zr->i2c_algo.data = zr;
+ zr->i2c_adapter.class = I2C_CLASS_TV_ANALOG;
zr->i2c_adapter.id = I2C_HW_B_ZR36067;
zr->i2c_adapter.client_register = zoran_i2c_client_register;
zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister;
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 25de7631443..db11ab9e60d 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -2996,7 +2996,6 @@ zoran_do_ioctl (struct inode *inode,
break;
default:
- dprintk(3, "unsupported\n");
dprintk(1,
KERN_ERR
"%s: VIDIOC_S_FMT - unsupported type %d\n",
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index 7cdac99deea..a1d81ed44c7 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -885,7 +885,7 @@ static int zr364xx_probe(struct usb_interface *intf,
usb_set_intfdata(intf, cam);
dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
- cam->vdev->minor);
+ cam->vdev->num);
return 0;
}
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 6e291bf8237..7911151e56a 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -172,9 +172,9 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error);
/*** Block device ***/
-static int mspro_block_bd_open(struct inode *inode, struct file *filp)
+static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct gendisk *disk = bdev->bd_disk;
struct mspro_block_data *msb = disk->private_data;
int rc = -ENXIO;
@@ -182,7 +182,7 @@ static int mspro_block_bd_open(struct inode *inode, struct file *filp)
if (msb && msb->card) {
msb->usage_count++;
- if ((filp->f_mode & FMODE_WRITE) && msb->read_only)
+ if ((mode & FMODE_WRITE) && msb->read_only)
rc = -EROFS;
else
rc = 0;
@@ -218,9 +218,8 @@ static int mspro_block_disk_release(struct gendisk *disk)
return 0;
}
-static int mspro_block_bd_release(struct inode *inode, struct file *filp)
+static int mspro_block_bd_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
return mspro_block_disk_release(disk);
}
@@ -1044,7 +1043,6 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
s_attr->dev_attr.attr.name = s_attr->name;
s_attr->dev_attr.attr.mode = S_IRUGO;
- s_attr->dev_attr.attr.owner = THIS_MODULE;
s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id);
if (!rc)
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index 81483de8c0f..11a617ab424 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -575,9 +575,9 @@ static void i2o_block_biosparam(unsigned long capacity, unsigned short *cyls,
*
* Returns 0 on success or negative error code on failure.
*/
-static int i2o_block_open(struct inode *inode, struct file *file)
+static int i2o_block_open(struct block_device *bdev, fmode_t mode)
{
- struct i2o_block_device *dev = inode->i_bdev->bd_disk->private_data;
+ struct i2o_block_device *dev = bdev->bd_disk->private_data;
if (!dev->i2o_dev)
return -ENODEV;
@@ -604,9 +604,8 @@ static int i2o_block_open(struct inode *inode, struct file *file)
*
* Returns 0 on success or negative error code on failure.
*/
-static int i2o_block_release(struct inode *inode, struct file *file)
+static int i2o_block_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
struct i2o_block_device *dev = disk->private_data;
u8 operation;
@@ -653,10 +652,10 @@ static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo)
*
* Return 0 on success or negative error on failure.
*/
-static int i2o_block_ioctl(struct inode *inode, struct file *file,
+static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct gendisk *disk = bdev->bd_disk;
struct i2o_block_device *dev = disk->private_data;
/* Anyone capable of this syscall can do *real bad* things */
@@ -933,7 +932,7 @@ static struct block_device_operations i2o_block_fops = {
.owner = THIS_MODULE,
.open = i2o_block_open,
.release = i2o_block_release,
- .ioctl = i2o_block_ioctl,
+ .locked_ioctl = i2o_block_ioctl,
.getgeo = i2o_block_getgeo,
.media_changed = i2o_block_media_changed
};
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 5eff8ad834d..5a79d2d4cda 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -52,6 +52,8 @@ config HTC_PASIC3
config UCB1400_CORE
tristate "Philips UCB1400 Core driver"
+ depends on AC97_BUS
+ depends on GPIOLIB
help
This enables support for the Philips UCB1400 core functions.
The UCB1400 is an AC97 audio codec.
@@ -59,6 +61,20 @@ config UCB1400_CORE
To compile this driver as a module, choose M here: the
module will be called ucb1400_core.
+config TWL4030_CORE
+ bool "Texas Instruments TWL4030/TPS659x0 Support"
+ depends on I2C=y && GENERIC_HARDIRQS && (ARCH_OMAP2 || ARCH_OMAP3)
+ help
+ Say yes here if you have TWL4030 family 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.
+
+ These multi-function chips are found on many OMAP2 and OMAP3
+ boards, providing power management, RTC, GPIO, keypad, a
+ high speed USB OTG transceiver, an audio codec (on most
+ versions) and many other features.
+
config MFD_TMIO
bool
default n
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 759b1fe1c89..0acefe8aff8 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -17,6 +17,8 @@ wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
+obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o
+
obj-$(CONFIG_MFD_CORE) += mfd-core.o
obj-$(CONFIG_MCP) += mcp-core.o
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index ba5aa200827..e4c0db4dc7b 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -123,7 +123,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
irqnr = asic->irq_base +
(ASIC3_GPIOS_PER_BANK * bank)
+ i;
- desc = irq_desc + irqnr;
+ desc = irq_to_desc(irqnr);
desc->handle_irq(irqnr, desc);
if (asic->irq_bothedge[bank] & bit)
asic3_irq_flip_edge(asic, base,
@@ -136,7 +136,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) {
/* They start at bit 4 and go up */
if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) {
- desc = irq_desc + asic->irq_base + i;
+ desc = irq_to_desc(asic->irq_base + i);
desc->handle_irq(asic->irq_base + i,
desc);
}
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c
new file mode 100644
index 00000000000..b57326ae464
--- /dev/null
+++ b/drivers/mfd/da903x.c
@@ -0,0 +1,563 @@
+/*
+ * Base driver for Dialog Semiconductor DA9030/DA9034
+ *
+ * Copyright (C) 2008 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Eric Miao <eric.miao@marvell.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/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/mfd/da903x.h>
+
+#define DA9030_CHIP_ID 0x00
+#define DA9030_EVENT_A 0x01
+#define DA9030_EVENT_B 0x02
+#define DA9030_EVENT_C 0x03
+#define DA9030_STATUS 0x04
+#define DA9030_IRQ_MASK_A 0x05
+#define DA9030_IRQ_MASK_B 0x06
+#define DA9030_IRQ_MASK_C 0x07
+#define DA9030_SYS_CTRL_A 0x08
+#define DA9030_SYS_CTRL_B 0x09
+#define DA9030_FAULT_LOG 0x0a
+
+#define DA9034_CHIP_ID 0x00
+#define DA9034_EVENT_A 0x01
+#define DA9034_EVENT_B 0x02
+#define DA9034_EVENT_C 0x03
+#define DA9034_EVENT_D 0x04
+#define DA9034_STATUS_A 0x05
+#define DA9034_STATUS_B 0x06
+#define DA9034_IRQ_MASK_A 0x07
+#define DA9034_IRQ_MASK_B 0x08
+#define DA9034_IRQ_MASK_C 0x09
+#define DA9034_IRQ_MASK_D 0x0a
+#define DA9034_SYS_CTRL_A 0x0b
+#define DA9034_SYS_CTRL_B 0x0c
+#define DA9034_FAULT_LOG 0x0d
+
+struct da903x_chip;
+
+struct da903x_chip_ops {
+ int (*init_chip)(struct da903x_chip *);
+ int (*unmask_events)(struct da903x_chip *, unsigned int events);
+ int (*mask_events)(struct da903x_chip *, unsigned int events);
+ int (*read_events)(struct da903x_chip *, unsigned int *events);
+ int (*read_status)(struct da903x_chip *, unsigned int *status);
+};
+
+struct da903x_chip {
+ struct i2c_client *client;
+ struct device *dev;
+ struct da903x_chip_ops *ops;
+
+ int type;
+ uint32_t events_mask;
+
+ struct mutex lock;
+ struct work_struct irq_work;
+
+ struct blocking_notifier_head notifier_list;
+};
+
+static inline int __da903x_read(struct i2c_client *client,
+ int reg, uint8_t *val)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
+ return ret;
+ }
+
+ *val = (uint8_t)ret;
+ return 0;
+}
+
+static inline int __da903x_reads(struct i2c_client *client, int reg,
+ int len, uint8_t *val)
+{
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
+ return ret;
+ }
+ return 0;
+}
+
+static inline int __da903x_write(struct i2c_client *client,
+ int reg, uint8_t val)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, reg, val);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
+ val, reg);
+ return ret;
+ }
+ return 0;
+}
+
+static inline int __da903x_writes(struct i2c_client *client, int reg,
+ int len, uint8_t *val)
+{
+ int ret;
+
+ ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
+ return ret;
+ }
+ return 0;
+}
+
+int da903x_register_notifier(struct device *dev, struct notifier_block *nb,
+ unsigned int events)
+{
+ struct da903x_chip *chip = dev_get_drvdata(dev);
+
+ chip->ops->unmask_events(chip, events);
+ return blocking_notifier_chain_register(&chip->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(da903x_register_notifier);
+
+int da903x_unregister_notifier(struct device *dev, struct notifier_block *nb,
+ unsigned int events)
+{
+ struct da903x_chip *chip = dev_get_drvdata(dev);
+
+ chip->ops->mask_events(chip, events);
+ return blocking_notifier_chain_unregister(&chip->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(da903x_unregister_notifier);
+
+int da903x_write(struct device *dev, int reg, uint8_t val)
+{
+ return __da903x_write(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(da903x_write);
+
+int da903x_read(struct device *dev, int reg, uint8_t *val)
+{
+ return __da903x_read(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(da903x_read);
+
+int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+ struct da903x_chip *chip = dev_get_drvdata(dev);
+ uint8_t reg_val;
+ int ret = 0;
+
+ mutex_lock(&chip->lock);
+
+ ret = __da903x_read(chip->client, reg, &reg_val);
+ if (ret)
+ goto out;
+
+ if ((reg_val & bit_mask) == 0) {
+ reg_val |= bit_mask;
+ ret = __da903x_write(chip->client, reg, reg_val);
+ }
+out:
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(da903x_set_bits);
+
+int da903x_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+ struct da903x_chip *chip = dev_get_drvdata(dev);
+ uint8_t reg_val;
+ int ret = 0;
+
+ mutex_lock(&chip->lock);
+
+ ret = __da903x_read(chip->client, reg, &reg_val);
+ if (ret)
+ goto out;
+
+ if (reg_val & bit_mask) {
+ reg_val &= ~bit_mask;
+ ret = __da903x_write(chip->client, reg, reg_val);
+ }
+out:
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(da903x_clr_bits);
+
+int da903x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
+{
+ struct da903x_chip *chip = dev_get_drvdata(dev);
+ uint8_t reg_val;
+ int ret = 0;
+
+ mutex_lock(&chip->lock);
+
+ ret = __da903x_read(chip->client, reg, &reg_val);
+ if (ret)
+ goto out;
+
+ if ((reg_val & mask) != val) {
+ reg_val = (reg_val & ~mask) | val;
+ ret = __da903x_write(chip->client, reg, reg_val);
+ }
+out:
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(da903x_update);
+
+int da903x_query_status(struct device *dev, unsigned int sbits)
+{
+ struct da903x_chip *chip = dev_get_drvdata(dev);
+ unsigned int status = 0;
+
+ chip->ops->read_status(chip, &status);
+ return ((status & sbits) == sbits);
+}
+EXPORT_SYMBOL(da903x_query_status);
+
+static int __devinit da9030_init_chip(struct da903x_chip *chip)
+{
+ uint8_t chip_id;
+ int err;
+
+ err = __da903x_read(chip->client, DA9030_CHIP_ID, &chip_id);
+ if (err)
+ return err;
+
+ err = __da903x_write(chip->client, DA9030_SYS_CTRL_A, 0xE8);
+ if (err)
+ return err;
+
+ dev_info(chip->dev, "DA9030 (CHIP ID: 0x%02x) detected\n", chip_id);
+ return 0;
+}
+
+static int da9030_unmask_events(struct da903x_chip *chip, unsigned int events)
+{
+ uint8_t v[3];
+
+ chip->events_mask &= ~events;
+
+ v[0] = (chip->events_mask & 0xff);
+ v[1] = (chip->events_mask >> 8) & 0xff;
+ v[2] = (chip->events_mask >> 16) & 0xff;
+
+ return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v);
+}
+
+static int da9030_mask_events(struct da903x_chip *chip, unsigned int events)
+{
+ uint8_t v[3];
+
+ chip->events_mask &= ~events;
+
+ v[0] = (chip->events_mask & 0xff);
+ v[1] = (chip->events_mask >> 8) & 0xff;
+ v[2] = (chip->events_mask >> 16) & 0xff;
+
+ return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v);
+}
+
+static int da9030_read_events(struct da903x_chip *chip, unsigned int *events)
+{
+ uint8_t v[3] = {0, 0, 0};
+ int ret;
+
+ ret = __da903x_reads(chip->client, DA9030_EVENT_A, 3, v);
+ if (ret < 0)
+ return ret;
+
+ *events = (v[2] << 16) | (v[1] << 8) | v[0];
+ return 0;
+}
+
+static int da9030_read_status(struct da903x_chip *chip, unsigned int *status)
+{
+ return __da903x_read(chip->client, DA9030_STATUS, (uint8_t *)status);
+}
+
+static int da9034_init_chip(struct da903x_chip *chip)
+{
+ uint8_t chip_id;
+ int err;
+
+ err = __da903x_read(chip->client, DA9034_CHIP_ID, &chip_id);
+ if (err)
+ return err;
+
+ err = __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0xE8);
+ if (err)
+ return err;
+
+ /* avoid SRAM power off during sleep*/
+ __da903x_write(chip->client, 0x10, 0x07);
+ __da903x_write(chip->client, 0x11, 0xff);
+ __da903x_write(chip->client, 0x12, 0xff);
+
+ /* Enable the ONKEY power down functionality */
+ __da903x_write(chip->client, DA9034_SYS_CTRL_B, 0x20);
+ __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0x60);
+
+ /* workaround to make LEDs work */
+ __da903x_write(chip->client, 0x90, 0x01);
+ __da903x_write(chip->client, 0xB0, 0x08);
+
+ /* make ADTV1 and SDTV1 effective */
+ __da903x_write(chip->client, 0x20, 0x00);
+
+ dev_info(chip->dev, "DA9034 (CHIP ID: 0x%02x) detected\n", chip_id);
+ return 0;
+}
+
+static int da9034_unmask_events(struct da903x_chip *chip, unsigned int events)
+{
+ uint8_t v[4];
+
+ chip->events_mask &= ~events;
+
+ v[0] = (chip->events_mask & 0xff);
+ v[1] = (chip->events_mask >> 8) & 0xff;
+ v[2] = (chip->events_mask >> 16) & 0xff;
+ v[3] = (chip->events_mask >> 24) & 0xff;
+
+ return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v);
+}
+
+static int da9034_mask_events(struct da903x_chip *chip, unsigned int events)
+{
+ uint8_t v[4];
+
+ chip->events_mask |= events;
+
+ v[0] = (chip->events_mask & 0xff);
+ v[1] = (chip->events_mask >> 8) & 0xff;
+ v[2] = (chip->events_mask >> 16) & 0xff;
+ v[3] = (chip->events_mask >> 24) & 0xff;
+
+ return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v);
+}
+
+static int da9034_read_events(struct da903x_chip *chip, unsigned int *events)
+{
+ uint8_t v[4] = {0, 0, 0, 0};
+ int ret;
+
+ ret = __da903x_reads(chip->client, DA9034_EVENT_A, 4, v);
+ if (ret < 0)
+ return ret;
+
+ *events = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0];
+ return 0;
+}
+
+static int da9034_read_status(struct da903x_chip *chip, unsigned int *status)
+{
+ uint8_t v[2] = {0, 0};
+ int ret = 0;
+
+ ret = __da903x_reads(chip->client, DA9034_STATUS_A, 2, v);
+ if (ret)
+ return ret;
+
+ *status = (v[1] << 8) | v[0];
+ return 0;
+}
+
+static void da903x_irq_work(struct work_struct *work)
+{
+ struct da903x_chip *chip =
+ container_of(work, struct da903x_chip, irq_work);
+ unsigned int events = 0;
+
+ while (1) {
+ if (chip->ops->read_events(chip, &events))
+ break;
+
+ events &= ~chip->events_mask;
+ if (events == 0)
+ break;
+
+ blocking_notifier_call_chain(
+ &chip->notifier_list, events, NULL);
+ }
+ enable_irq(chip->client->irq);
+}
+
+static int da903x_irq_handler(int irq, void *data)
+{
+ struct da903x_chip *chip = data;
+
+ disable_irq_nosync(irq);
+ (void)schedule_work(&chip->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static struct da903x_chip_ops da903x_ops[] = {
+ [0] = {
+ .init_chip = da9030_init_chip,
+ .unmask_events = da9030_unmask_events,
+ .mask_events = da9030_mask_events,
+ .read_events = da9030_read_events,
+ .read_status = da9030_read_status,
+ },
+ [1] = {
+ .init_chip = da9034_init_chip,
+ .unmask_events = da9034_unmask_events,
+ .mask_events = da9034_mask_events,
+ .read_events = da9034_read_events,
+ .read_status = da9034_read_status,
+ }
+};
+
+static const struct i2c_device_id da903x_id_table[] = {
+ { "da9030", 0 },
+ { "da9034", 1 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, da903x_id_table);
+
+static int __devexit __remove_subdev(struct device *dev, void *unused)
+{
+ platform_device_unregister(to_platform_device(dev));
+ return 0;
+}
+
+static int __devexit da903x_remove_subdevs(struct da903x_chip *chip)
+{
+ return device_for_each_child(chip->dev, NULL, __remove_subdev);
+}
+
+static int __devinit da903x_add_subdevs(struct da903x_chip *chip,
+ struct da903x_platform_data *pdata)
+{
+ struct da903x_subdev_info *subdev;
+ struct platform_device *pdev;
+ int i, ret = 0;
+
+ for (i = 0; i < pdata->num_subdevs; i++) {
+ subdev = &pdata->subdevs[i];
+
+ pdev = platform_device_alloc(subdev->name, subdev->id);
+
+ pdev->dev.parent = chip->dev;
+ pdev->dev.platform_data = subdev->platform_data;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto failed;
+ }
+ return 0;
+
+failed:
+ da903x_remove_subdevs(chip);
+ return ret;
+}
+
+static int __devinit da903x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct da903x_platform_data *pdata = client->dev.platform_data;
+ struct da903x_chip *chip;
+ unsigned int tmp;
+ int ret;
+
+ chip = kzalloc(sizeof(struct da903x_chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
+ chip->client = client;
+ chip->dev = &client->dev;
+ chip->ops = &da903x_ops[id->driver_data];
+
+ mutex_init(&chip->lock);
+ INIT_WORK(&chip->irq_work, da903x_irq_work);
+ BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list);
+
+ i2c_set_clientdata(client, chip);
+
+ ret = chip->ops->init_chip(chip);
+ if (ret)
+ goto out_free_chip;
+
+ /* mask and clear all IRQs */
+ chip->events_mask = 0xffffffff;
+ chip->ops->mask_events(chip, chip->events_mask);
+ chip->ops->read_events(chip, &tmp);
+
+ ret = request_irq(client->irq, da903x_irq_handler,
+ IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+ "da903x", chip);
+ if (ret) {
+ dev_err(&client->dev, "failed to request irq %d\n",
+ client->irq);
+ goto out_free_chip;
+ }
+
+ ret = da903x_add_subdevs(chip, pdata);
+ if (ret)
+ goto out_free_irq;
+
+ return 0;
+
+out_free_irq:
+ free_irq(client->irq, chip);
+out_free_chip:
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return ret;
+}
+
+static int __devexit da903x_remove(struct i2c_client *client)
+{
+ struct da903x_chip *chip = i2c_get_clientdata(client);
+
+ da903x_remove_subdevs(chip);
+ kfree(chip);
+ return 0;
+}
+
+static struct i2c_driver da903x_driver = {
+ .driver = {
+ .name = "da903x",
+ .owner = THIS_MODULE,
+ },
+ .probe = da903x_probe,
+ .remove = __devexit_p(da903x_remove),
+ .id_table = da903x_id_table,
+};
+
+static int __init da903x_init(void)
+{
+ return i2c_add_driver(&da903x_driver);
+}
+module_init(da903x_init);
+
+static void __exit da903x_exit(void)
+{
+ i2c_del_driver(&da903x_driver);
+}
+module_exit(da903x_exit);
+
+MODULE_DESCRIPTION("PMIC Driver for Dialog Semiconductor DA9034");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
+ "Mike Rapoport <mike@compulab.co.il>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
index 6be43172dc6..1a4d04664d6 100644
--- a/drivers/mfd/htc-egpio.c
+++ b/drivers/mfd/htc-egpio.c
@@ -112,7 +112,7 @@ static void egpio_handler(unsigned int irq, struct irq_desc *desc)
/* Run irq handler */
pr_debug("got IRQ %d\n", irqpin);
irq = ei->irq_start + irqpin;
- desc = &irq_desc[irq];
+ desc = irq_to_desc(irq);
desc->handle_irq(irq, desc);
}
}
@@ -289,7 +289,7 @@ static int __init egpio_probe(struct platform_device *pdev)
ei->base_addr = ioremap_nocache(res->start, res->end - res->start);
if (!ei->base_addr)
goto fail;
- pr_debug("EGPIO phys=%08x virt=%p\n", res->start, ei->base_addr);
+ pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
goto fail;
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 9c9c126ed33..6c0d1bec4b7 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -20,7 +20,7 @@ static int mfd_add_device(struct device *parent, int id,
struct resource *mem_base,
int irq_base)
{
- struct resource res[cell->num_resources];
+ struct resource *res;
struct platform_device *pdev;
int ret = -ENOMEM;
int r;
@@ -29,14 +29,17 @@ static int mfd_add_device(struct device *parent, int id,
if (!pdev)
goto fail_alloc;
+ res = kzalloc(sizeof(*res) * cell->num_resources, GFP_KERNEL);
+ if (!res)
+ goto fail_device;
+
pdev->dev.parent = parent;
ret = platform_device_add_data(pdev,
cell->platform_data, cell->data_size);
if (ret)
- goto fail_device;
+ goto fail_res;
- memset(res, 0, sizeof(res));
for (r = 0; r < cell->num_resources; r++) {
res[r].name = cell->resources[r].name;
res[r].flags = cell->resources[r].flags;
@@ -64,11 +67,15 @@ static int mfd_add_device(struct device *parent, int id,
ret = platform_device_add(pdev);
if (ret)
- goto fail_device;
+ goto fail_res;
+
+ kfree(res);
return 0;
/* platform_device_del(pdev); */
+fail_res:
+ kfree(res);
fail_device:
platform_device_put(pdev);
fail_alloc:
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 7aebad4c06f..170f9d47c2f 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -623,8 +623,8 @@ unsigned long sm501_set_clock(struct device *dev,
sm501_sync_regs(sm);
- dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
- gate, clock, mode);
+ dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
+ gate, clock, mode);
sm501_mdelay(sm, 16);
mutex_unlock(&sm->clock_lock);
@@ -742,7 +742,7 @@ static int sm501_register_device(struct sm501_devdata *sm,
int ret;
for (ptr = 0; ptr < pdev->num_resources; ptr++) {
- printk("%s[%d] flags %08lx: %08llx..%08llx\n",
+ printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n",
pdev->name, ptr,
pdev->resource[ptr].flags,
(unsigned long long)pdev->resource[ptr].start,
@@ -1374,31 +1374,31 @@ static int sm501_init_dev(struct sm501_devdata *sm)
static int sm501_plat_probe(struct platform_device *dev)
{
struct sm501_devdata *sm;
- int err;
+ int ret;
sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL);
if (sm == NULL) {
dev_err(&dev->dev, "no memory for device data\n");
- err = -ENOMEM;
+ ret = -ENOMEM;
goto err1;
}
sm->dev = &dev->dev;
sm->pdev_id = dev->id;
- sm->irq = platform_get_irq(dev, 0);
- sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
- sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
sm->platdata = dev->dev.platform_data;
- if (sm->irq < 0) {
+ ret = platform_get_irq(dev, 0);
+ if (ret < 0) {
dev_err(&dev->dev, "failed to get irq resource\n");
- err = sm->irq;
goto err_res;
}
+ sm->irq = ret;
+ sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+ sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (sm->io_res == NULL || sm->mem_res == NULL) {
dev_err(&dev->dev, "failed to get IO resource\n");
- err = -ENOENT;
+ ret = -ENOENT;
goto err_res;
}
@@ -1407,7 +1407,7 @@ static int sm501_plat_probe(struct platform_device *dev)
if (sm->regs_claim == NULL) {
dev_err(&dev->dev, "cannot claim registers\n");
- err= -EBUSY;
+ ret = -EBUSY;
goto err_res;
}
@@ -1418,7 +1418,7 @@ static int sm501_plat_probe(struct platform_device *dev)
if (sm->regs == NULL) {
dev_err(&dev->dev, "cannot remap registers\n");
- err = -EIO;
+ ret = -EIO;
goto err_claim;
}
@@ -1430,7 +1430,7 @@ static int sm501_plat_probe(struct platform_device *dev)
err_res:
kfree(sm);
err1:
- return err;
+ return ret;
}
@@ -1625,8 +1625,7 @@ static int sm501_pci_probe(struct pci_dev *dev,
goto err3;
}
- sm->regs = ioremap(pci_resource_start(dev, 1),
- pci_resource_len(dev, 1));
+ sm->regs = pci_ioremap_bar(dev, 1);
if (sm->regs == NULL) {
dev_err(&dev->dev, "cannot remap registers\n");
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 49a0fffc02a..9f7024c0f8e 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -24,8 +24,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
@@ -56,6 +58,8 @@ struct t7l66xb {
spinlock_t lock;
struct resource rscr;
+ struct clk *clk48m;
+ struct clk *clk32k;
int irq;
int irq_base;
};
@@ -65,13 +69,11 @@ struct t7l66xb {
static int t7l66xb_mmc_enable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
unsigned long flags;
u8 dev_ctl;
- if (pdata->enable_clk32k)
- pdata->enable_clk32k(dev);
+ clk_enable(t7l66xb->clk32k);
spin_lock_irqsave(&t7l66xb->lock, flags);
@@ -87,7 +89,6 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
static int t7l66xb_mmc_disable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
unsigned long flags;
u8 dev_ctl;
@@ -100,8 +101,7 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
spin_unlock_irqrestore(&t7l66xb->lock, flags);
- if (pdata->disable_clk32k)
- pdata->disable_clk32k(dev);
+ clk_disable(t7l66xb->clk32k);
return 0;
}
@@ -258,18 +258,22 @@ static void t7l66xb_detach_irq(struct platform_device *dev)
#ifdef CONFIG_PM
static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
{
+ struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
if (pdata && pdata->suspend)
pdata->suspend(dev);
+ clk_disable(t7l66xb->clk48m);
return 0;
}
static int t7l66xb_resume(struct platform_device *dev)
{
+ struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
+ clk_enable(t7l66xb->clk48m);
if (pdata && pdata->resume)
pdata->resume(dev);
@@ -309,6 +313,19 @@ static int t7l66xb_probe(struct platform_device *dev)
t7l66xb->irq_base = pdata->irq_base;
+ t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K");
+ if (IS_ERR(t7l66xb->clk32k)) {
+ ret = PTR_ERR(t7l66xb->clk32k);
+ goto err_clk32k_get;
+ }
+
+ t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M");
+ if (IS_ERR(t7l66xb->clk48m)) {
+ ret = PTR_ERR(t7l66xb->clk48m);
+ clk_put(t7l66xb->clk32k);
+ goto err_clk48m_get;
+ }
+
rscr = &t7l66xb->rscr;
rscr->name = "t7l66xb-core";
rscr->start = iomem->start;
@@ -325,6 +342,8 @@ static int t7l66xb_probe(struct platform_device *dev)
goto err_ioremap;
}
+ clk_enable(t7l66xb->clk48m);
+
if (pdata && pdata->enable)
pdata->enable(dev);
@@ -359,9 +378,13 @@ static int t7l66xb_probe(struct platform_device *dev)
iounmap(t7l66xb->scr);
err_ioremap:
release_resource(&t7l66xb->rscr);
-err_noirq:
err_request_scr:
kfree(t7l66xb);
+ clk_put(t7l66xb->clk48m);
+err_clk48m_get:
+ clk_put(t7l66xb->clk32k);
+err_clk32k_get:
+err_noirq:
return ret;
}
@@ -372,7 +395,8 @@ static int t7l66xb_remove(struct platform_device *dev)
int ret;
ret = pdata->disable(dev);
-
+ clk_disable(t7l66xb->clk48m);
+ clk_put(t7l66xb->clk48m);
t7l66xb_detach_irq(dev);
iounmap(t7l66xb->scr);
release_resource(&t7l66xb->rscr);
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index a22b21ac6cf..43222c12fec 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
@@ -24,18 +25,22 @@ enum {
#ifdef CONFIG_PM
static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
{
- struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev);
+ struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
if (pdata && pdata->suspend)
pdata->suspend(dev);
+ clk_disable(clk32k);
return 0;
}
static int tc6387xb_resume(struct platform_device *dev)
{
- struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev);
+ struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
+ clk_enable(clk32k);
if (pdata && pdata->resume)
pdata->resume(dev);
@@ -51,10 +56,9 @@ static int tc6387xb_resume(struct platform_device *dev)
static int tc6387xb_mmc_enable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data;
+ struct clk *clk32k = platform_get_drvdata(dev);
- if (tc6387xb->enable_clk32k)
- tc6387xb->enable_clk32k(dev);
+ clk_enable(clk32k);
return 0;
}
@@ -62,10 +66,9 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
static int tc6387xb_mmc_disable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data;
+ struct clk *clk32k = platform_get_drvdata(dev);
- if (tc6387xb->disable_clk32k)
- tc6387xb->disable_clk32k(dev);
+ clk_disable(clk32k);
return 0;
}
@@ -102,14 +105,14 @@ static struct mfd_cell tc6387xb_cells[] = {
static int tc6387xb_probe(struct platform_device *dev)
{
- struct tc6387xb_platform_data *data = platform_get_drvdata(dev);
+ struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
struct resource *iomem;
+ struct clk *clk32k;
int irq, ret;
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!iomem) {
- ret = -EINVAL;
- goto err_resource;
+ return -EINVAL;
}
ret = platform_get_irq(dev, 0);
@@ -118,8 +121,15 @@ static int tc6387xb_probe(struct platform_device *dev)
else
goto err_resource;
- if (data && data->enable)
- data->enable(dev);
+ clk32k = clk_get(&dev->dev, "CLK_CK32K");
+ if (IS_ERR(clk32k)) {
+ ret = PTR_ERR(clk32k);
+ goto err_resource;
+ }
+ platform_set_drvdata(dev, clk32k);
+
+ if (pdata && pdata->enable)
+ pdata->enable(dev);
printk(KERN_INFO "Toshiba tc6387xb initialised\n");
@@ -134,18 +144,19 @@ static int tc6387xb_probe(struct platform_device *dev)
if (!ret)
return 0;
+ clk_put(clk32k);
err_resource:
return ret;
}
static int tc6387xb_remove(struct platform_device *dev)
{
- struct tc6387xb_platform_data *data = platform_get_drvdata(dev);
-
- if (data && data->disable)
- data->disable(dev);
+ struct clk *clk32k = platform_get_drvdata(dev);
- /* FIXME - free the resources! */
+ mfd_remove_devices(&dev->dev);
+ clk_disable(clk32k);
+ clk_put(clk32k);
+ platform_set_drvdata(dev, NULL);
return 0;
}
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index e4c1c788b5f..f856e9463a9 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -113,6 +113,8 @@ struct tc6393xb {
enum {
TC6393XB_CELL_NAND,
TC6393XB_CELL_MMC,
+ TC6393XB_CELL_OHCI,
+ TC6393XB_CELL_FB,
};
/*--------------------------------------------------------------------------*/
@@ -170,6 +172,176 @@ static struct resource __devinitdata tc6393xb_mmc_resources[] = {
},
};
+const static struct resource tc6393xb_ohci_resources[] = {
+ {
+ .start = 0x3000,
+ .end = 0x31ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x0300,
+ .end = 0x03ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x010000,
+ .end = 0x017fff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x018000,
+ .end = 0x01ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TC6393_OHCI,
+ .end = IRQ_TC6393_OHCI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource __devinitdata tc6393xb_fb_resources[] = {
+ {
+ .start = 0x5000,
+ .end = 0x51ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x0500,
+ .end = 0x05ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x100000,
+ .end = 0x1fffff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TC6393_FB,
+ .end = IRQ_TC6393_FB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int tc6393xb_ohci_enable(struct platform_device *dev)
+{
+ struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
+ unsigned long flags;
+ u16 ccr;
+ u8 fer;
+
+ spin_lock_irqsave(&tc6393xb->lock, flags);
+
+ ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
+ ccr |= SCR_CCR_USBCK;
+ tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
+
+ fer = tmio_ioread8(tc6393xb->scr + SCR_FER);
+ fer |= SCR_FER_USBEN;
+ tmio_iowrite8(fer, tc6393xb->scr + SCR_FER);
+
+ spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+ return 0;
+}
+
+static int tc6393xb_ohci_disable(struct platform_device *dev)
+{
+ struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
+ unsigned long flags;
+ u16 ccr;
+ u8 fer;
+
+ spin_lock_irqsave(&tc6393xb->lock, flags);
+
+ fer = tmio_ioread8(tc6393xb->scr + SCR_FER);
+ fer &= ~SCR_FER_USBEN;
+ tmio_iowrite8(fer, tc6393xb->scr + SCR_FER);
+
+ ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
+ ccr &= ~SCR_CCR_USBCK;
+ tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
+
+ spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+ return 0;
+}
+
+static int tc6393xb_fb_enable(struct platform_device *dev)
+{
+ struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
+ unsigned long flags;
+ u16 ccr;
+
+ spin_lock_irqsave(&tc6393xb->lock, flags);
+
+ ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
+ ccr &= ~SCR_CCR_MCLK_MASK;
+ ccr |= SCR_CCR_MCLK_48;
+ tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
+
+ spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+ return 0;
+}
+
+static int tc6393xb_fb_disable(struct platform_device *dev)
+{
+ struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
+ unsigned long flags;
+ u16 ccr;
+
+ spin_lock_irqsave(&tc6393xb->lock, flags);
+
+ ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
+ ccr &= ~SCR_CCR_MCLK_MASK;
+ ccr |= SCR_CCR_MCLK_OFF;
+ tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
+
+ spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+ return 0;
+}
+
+int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
+{
+ struct platform_device *dev = to_platform_device(fb->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+ u8 fer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tc6393xb->lock, flags);
+
+ fer = ioread8(tc6393xb->scr + SCR_FER);
+ if (on)
+ fer |= SCR_FER_SLCDEN;
+ else
+ fer &= ~SCR_FER_SLCDEN;
+ iowrite8(fer, tc6393xb->scr + SCR_FER);
+
+ spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(tc6393xb_lcd_set_power);
+
+int tc6393xb_lcd_mode(struct platform_device *fb,
+ const struct fb_videomode *mode) {
+ struct platform_device *dev = to_platform_device(fb->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&tc6393xb->lock, flags);
+
+ iowrite16(mode->pixclock, tc6393xb->scr + SCR_PLL1CR + 0);
+ iowrite16(mode->pixclock >> 16, tc6393xb->scr + SCR_PLL1CR + 2);
+
+ spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(tc6393xb_lcd_mode);
+
static struct mfd_cell __devinitdata tc6393xb_cells[] = {
[TC6393XB_CELL_NAND] = {
.name = "tmio-nand",
@@ -182,6 +354,24 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
.num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
.resources = tc6393xb_mmc_resources,
},
+ [TC6393XB_CELL_OHCI] = {
+ .name = "tmio-ohci",
+ .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources),
+ .resources = tc6393xb_ohci_resources,
+ .enable = tc6393xb_ohci_enable,
+ .suspend = tc6393xb_ohci_disable,
+ .resume = tc6393xb_ohci_enable,
+ .disable = tc6393xb_ohci_disable,
+ },
+ [TC6393XB_CELL_FB] = {
+ .name = "tmio-fb",
+ .num_resources = ARRAY_SIZE(tc6393xb_fb_resources),
+ .resources = tc6393xb_fb_resources,
+ .enable = tc6393xb_fb_enable,
+ .suspend = tc6393xb_fb_disable,
+ .resume = tc6393xb_fb_enable,
+ .disable = tc6393xb_fb_disable,
+ },
};
/*--------------------------------------------------------------------------*/
@@ -369,41 +559,12 @@ static void tc6393xb_detach_irq(struct platform_device *dev)
/*--------------------------------------------------------------------------*/
-static int tc6393xb_hw_init(struct platform_device *dev)
-{
- struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
- struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
- int i;
-
- iowrite8(tc6393xb->suspend_state.fer, tc6393xb->scr + SCR_FER);
- iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR);
- iowrite16(tc6393xb->suspend_state.ccr, tc6393xb->scr + SCR_CCR);
- iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN |
- SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN |
- BIT(15), tc6393xb->scr + SCR_MCR);
- iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER);
- iowrite8(0, tc6393xb->scr + SCR_IRR);
- iowrite8(0xbf, tc6393xb->scr + SCR_IMR);
-
- for (i = 0; i < 3; i++) {
- iowrite8(tc6393xb->suspend_state.gpo_dsr[i],
- tc6393xb->scr + SCR_GPO_DSR(i));
- iowrite8(tc6393xb->suspend_state.gpo_doecr[i],
- tc6393xb->scr + SCR_GPO_DOECR(i));
- iowrite8(tc6393xb->suspend_state.gpi_bcr[i],
- tc6393xb->scr + SCR_GPI_BCR(i));
- }
-
- return 0;
-}
-
static int __devinit tc6393xb_probe(struct platform_device *dev)
{
struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
struct tc6393xb *tc6393xb;
struct resource *iomem, *rscr;
int ret, temp;
- int i;
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!iomem)
@@ -458,21 +619,16 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
if (ret)
goto err_enable;
- tc6393xb->suspend_state.fer = 0;
-
- for (i = 0; i < 3; i++) {
- tc6393xb->suspend_state.gpo_dsr[i] =
- (tcpd->scr_gpo_dsr >> (8 * i)) & 0xff;
- tc6393xb->suspend_state.gpo_doecr[i] =
- (tcpd->scr_gpo_doecr >> (8 * i)) & 0xff;
- }
-
- tc6393xb->suspend_state.ccr = SCR_CCR_UNK1 |
- SCR_CCR_HCLK_48;
-
- ret = tc6393xb_hw_init(dev);
- if (ret)
- goto err_hw_init;
+ iowrite8(0, tc6393xb->scr + SCR_FER);
+ iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR);
+ iowrite16(SCR_CCR_UNK1 | SCR_CCR_HCLK_48,
+ tc6393xb->scr + SCR_CCR);
+ iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN |
+ SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN |
+ BIT(15), tc6393xb->scr + SCR_MCR);
+ iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER);
+ iowrite8(0, tc6393xb->scr + SCR_IRR);
+ iowrite8(0xbf, tc6393xb->scr + SCR_IMR);
printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n",
tmio_ioread8(tc6393xb->scr + SCR_REVID),
@@ -488,16 +644,33 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
tc6393xb_attach_irq(dev);
+ if (tcpd->setup) {
+ ret = tcpd->setup(dev);
+ if (ret)
+ goto err_setup;
+ }
+
tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data;
tc6393xb_cells[TC6393XB_CELL_NAND].platform_data =
&tc6393xb_cells[TC6393XB_CELL_NAND];
tc6393xb_cells[TC6393XB_CELL_NAND].data_size =
sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]);
+
tc6393xb_cells[TC6393XB_CELL_MMC].platform_data =
&tc6393xb_cells[TC6393XB_CELL_MMC];
tc6393xb_cells[TC6393XB_CELL_MMC].data_size =
sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]);
+ tc6393xb_cells[TC6393XB_CELL_OHCI].platform_data =
+ &tc6393xb_cells[TC6393XB_CELL_OHCI];
+ tc6393xb_cells[TC6393XB_CELL_OHCI].data_size =
+ sizeof(tc6393xb_cells[TC6393XB_CELL_OHCI]);
+
+ tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data;
+ tc6393xb_cells[TC6393XB_CELL_FB].platform_data =
+ &tc6393xb_cells[TC6393XB_CELL_FB];
+ tc6393xb_cells[TC6393XB_CELL_FB].data_size =
+ sizeof(tc6393xb_cells[TC6393XB_CELL_FB]);
ret = mfd_add_devices(&dev->dev, dev->id,
tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
@@ -506,12 +679,15 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
if (!ret)
return 0;
+ if (tcpd->teardown)
+ tcpd->teardown(dev);
+
+err_setup:
tc6393xb_detach_irq(dev);
err_gpio_add:
if (tc6393xb->gpio.base != -1)
temp = gpiochip_remove(&tc6393xb->gpio);
-err_hw_init:
tcpd->disable(dev);
err_clk_enable:
clk_disable(tc6393xb->clk);
@@ -535,6 +711,10 @@ static int __devexit tc6393xb_remove(struct platform_device *dev)
int ret;
mfd_remove_devices(&dev->dev);
+
+ if (tcpd->teardown)
+ tcpd->teardown(dev);
+
tc6393xb_detach_irq(dev);
if (tc6393xb->gpio.base != -1) {
@@ -585,15 +765,37 @@ static int tc6393xb_resume(struct platform_device *dev)
struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
int ret;
+ int i;
clk_enable(tc6393xb->clk);
ret = tcpd->resume(dev);
-
if (ret)
return ret;
- return tc6393xb_hw_init(dev);
+ if (!tcpd->resume_restore)
+ return 0;
+
+ iowrite8(tc6393xb->suspend_state.fer, tc6393xb->scr + SCR_FER);
+ iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR);
+ iowrite16(tc6393xb->suspend_state.ccr, tc6393xb->scr + SCR_CCR);
+ iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN |
+ SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN |
+ BIT(15), tc6393xb->scr + SCR_MCR);
+ iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER);
+ iowrite8(0, tc6393xb->scr + SCR_IRR);
+ iowrite8(0xbf, tc6393xb->scr + SCR_IMR);
+
+ for (i = 0; i < 3; i++) {
+ iowrite8(tc6393xb->suspend_state.gpo_dsr[i],
+ tc6393xb->scr + SCR_GPO_DSR(i));
+ iowrite8(tc6393xb->suspend_state.gpo_doecr[i],
+ tc6393xb->scr + SCR_GPO_DOECR(i));
+ iowrite8(tc6393xb->suspend_state.gpi_bcr[i],
+ tc6393xb->scr + SCR_GPI_BCR(i));
+ }
+
+ return 0;
}
#else
#define tc6393xb_suspend NULL
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
new file mode 100644
index 00000000000..dd843c4fbcc
--- /dev/null
+++ b/drivers/mfd/twl4030-core.c
@@ -0,0 +1,806 @@
+/*
+ * twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Modifications to defer interrupt handling to a kernel thread:
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Code cleanup and modifications to IRQ handler.
+ * by syed khasim <x0khasim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
+ * Management and System Companion Device" chips originally designed for
+ * use in OMAP2 and OMAP 3 based systems. Its control interfaces use I2C,
+ * often at around 3 Mbit/sec, including for interrupt handling.
+ *
+ * This driver core provides genirq support for the interrupts emitted,
+ * by the various modules, and exports register access primitives.
+ *
+ * FIXME this driver currently requires use of the first interrupt line
+ * (and associated registers).
+ */
+
+#define DRIVER_NAME "twl4030"
+
+#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
+ defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
+#define twl_has_bci() true
+#else
+#define twl_has_bci() false
+#endif
+
+#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
+#define twl_has_keypad() true
+#else
+#define twl_has_keypad() false
+#endif
+
+#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE)
+#define twl_has_gpio() true
+#else
+#define twl_has_gpio() false
+#endif
+
+#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
+#define twl_has_madc() true
+#else
+#define twl_has_madc() false
+#endif
+
+#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
+#define twl_has_rtc() true
+#else
+#define twl_has_rtc() false
+#endif
+
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#define twl_has_usb() true
+#else
+#define twl_has_usb() false
+#endif
+
+
+/* Triton Core internal information (BEGIN) */
+
+/* Last - for index max*/
+#define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG
+
+#define TWL4030_NUM_SLAVES 4
+
+
+/* Base Address defns for twl4030_map[] */
+
+/* subchip/slave 0 - USB ID */
+#define TWL4030_BASEADD_USB 0x0000
+
+/* subchip/slave 1 - AUD ID */
+#define TWL4030_BASEADD_AUDIO_VOICE 0x0000
+#define TWL4030_BASEADD_GPIO 0x0098
+#define TWL4030_BASEADD_INTBR 0x0085
+#define TWL4030_BASEADD_PIH 0x0080
+#define TWL4030_BASEADD_TEST 0x004C
+
+/* subchip/slave 2 - AUX ID */
+#define TWL4030_BASEADD_INTERRUPTS 0x00B9
+#define TWL4030_BASEADD_LED 0x00EE
+#define TWL4030_BASEADD_MADC 0x0000
+#define TWL4030_BASEADD_MAIN_CHARGE 0x0074
+#define TWL4030_BASEADD_PRECHARGE 0x00AA
+#define TWL4030_BASEADD_PWM0 0x00F8
+#define TWL4030_BASEADD_PWM1 0x00FB
+#define TWL4030_BASEADD_PWMA 0x00EF
+#define TWL4030_BASEADD_PWMB 0x00F1
+#define TWL4030_BASEADD_KEYPAD 0x00D2
+
+/* subchip/slave 3 - POWER ID */
+#define TWL4030_BASEADD_BACKUP 0x0014
+#define TWL4030_BASEADD_INT 0x002E
+#define TWL4030_BASEADD_PM_MASTER 0x0036
+#define TWL4030_BASEADD_PM_RECEIVER 0x005B
+#define TWL4030_BASEADD_RTC 0x001C
+#define TWL4030_BASEADD_SECURED_REG 0x0000
+
+/* Triton Core internal information (END) */
+
+
+/* Few power values */
+#define R_CFG_BOOT 0x05
+#define R_PROTECT_KEY 0x0E
+
+/* access control values for R_PROTECT_KEY */
+#define KEY_UNLOCK1 0xce
+#define KEY_UNLOCK2 0xec
+#define KEY_LOCK 0x00
+
+/* some fields in R_CFG_BOOT */
+#define HFCLK_FREQ_19p2_MHZ (1 << 0)
+#define HFCLK_FREQ_26_MHZ (2 << 0)
+#define HFCLK_FREQ_38p4_MHZ (3 << 0)
+#define HIGH_PERF_SQ (1 << 3)
+
+
+/*----------------------------------------------------------------------*/
+
+/* is driver active, bound to a chip? */
+static bool inuse;
+
+/* Structure for each TWL4030 Slave */
+struct twl4030_client {
+ struct i2c_client *client;
+ u8 address;
+
+ /* max numb of i2c_msg required is for read =2 */
+ struct i2c_msg xfer_msg[2];
+
+ /* To lock access to xfer_msg */
+ struct mutex xfer_lock;
+};
+
+static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES];
+
+
+/* mapping the module id to slave id and base address */
+struct twl4030mapping {
+ unsigned char sid; /* Slave ID */
+ unsigned char base; /* base address */
+};
+
+static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
+ /*
+ * NOTE: don't change this table without updating the
+ * <linux/i2c/twl4030.h> defines for TWL4030_MODULE_*
+ * so they continue to match the order in this table.
+ */
+
+ { 0, TWL4030_BASEADD_USB },
+
+ { 1, TWL4030_BASEADD_AUDIO_VOICE },
+ { 1, TWL4030_BASEADD_GPIO },
+ { 1, TWL4030_BASEADD_INTBR },
+ { 1, TWL4030_BASEADD_PIH },
+ { 1, TWL4030_BASEADD_TEST },
+
+ { 2, TWL4030_BASEADD_KEYPAD },
+ { 2, TWL4030_BASEADD_MADC },
+ { 2, TWL4030_BASEADD_INTERRUPTS },
+ { 2, TWL4030_BASEADD_LED },
+ { 2, TWL4030_BASEADD_MAIN_CHARGE },
+ { 2, TWL4030_BASEADD_PRECHARGE },
+ { 2, TWL4030_BASEADD_PWM0 },
+ { 2, TWL4030_BASEADD_PWM1 },
+ { 2, TWL4030_BASEADD_PWMA },
+ { 2, TWL4030_BASEADD_PWMB },
+
+ { 3, TWL4030_BASEADD_BACKUP },
+ { 3, TWL4030_BASEADD_INT },
+ { 3, TWL4030_BASEADD_PM_MASTER },
+ { 3, TWL4030_BASEADD_PM_RECEIVER },
+ { 3, TWL4030_BASEADD_RTC },
+ { 3, TWL4030_BASEADD_SECURED_REG },
+};
+
+/*----------------------------------------------------------------------*/
+
+/* Exported Functions */
+
+/**
+ * twl4030_i2c_write - Writes a n bit register in TWL4030
+ * @mod_no: module number
+ * @value: an array of num_bytes+1 containing data to write
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
+ * valid data starts at Offset 1.
+ *
+ * Returns the result of operation - 0 is success
+ */
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+ int ret;
+ int sid;
+ struct twl4030_client *twl;
+ struct i2c_msg *msg;
+
+ if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+ pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+ return -EPERM;
+ }
+ sid = twl4030_map[mod_no].sid;
+ twl = &twl4030_modules[sid];
+
+ if (unlikely(!inuse)) {
+ pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+ return -EPERM;
+ }
+ mutex_lock(&twl->xfer_lock);
+ /*
+ * [MSG1]: fill the register address data
+ * fill the data Tx buffer
+ */
+ msg = &twl->xfer_msg[0];
+ msg->addr = twl->address;
+ msg->len = num_bytes + 1;
+ msg->flags = 0;
+ msg->buf = value;
+ /* over write the first byte of buffer with the register address */
+ *value = twl4030_map[mod_no].base + reg;
+ ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1);
+ mutex_unlock(&twl->xfer_lock);
+
+ /* i2cTransfer returns num messages.translate it pls.. */
+ if (ret >= 0)
+ ret = 0;
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_write);
+
+/**
+ * twl4030_i2c_read - Reads a n bit register in TWL4030
+ * @mod_no: module number
+ * @value: an array of num_bytes containing data to be read
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * Returns result of operation - num_bytes is success else failure.
+ */
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+ int ret;
+ u8 val;
+ int sid;
+ struct twl4030_client *twl;
+ struct i2c_msg *msg;
+
+ if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+ pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+ return -EPERM;
+ }
+ sid = twl4030_map[mod_no].sid;
+ twl = &twl4030_modules[sid];
+
+ if (unlikely(!inuse)) {
+ pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+ return -EPERM;
+ }
+ mutex_lock(&twl->xfer_lock);
+ /* [MSG1] fill the register address data */
+ msg = &twl->xfer_msg[0];
+ msg->addr = twl->address;
+ msg->len = 1;
+ msg->flags = 0; /* Read the register value */
+ val = twl4030_map[mod_no].base + reg;
+ msg->buf = &val;
+ /* [MSG2] fill the data rx buffer */
+ msg = &twl->xfer_msg[1];
+ msg->addr = twl->address;
+ msg->flags = I2C_M_RD; /* Read the register value */
+ msg->len = num_bytes; /* only n bytes */
+ msg->buf = value;
+ ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2);
+ mutex_unlock(&twl->xfer_lock);
+
+ /* i2cTransfer returns num messages.translate it pls.. */
+ if (ret >= 0)
+ ret = 0;
+ return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_read);
+
+/**
+ * twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030
+ * @mod_no: module number
+ * @value: the value to be written 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
+{
+
+ /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
+ u8 temp_buffer[2] = { 0 };
+ /* offset 1 contains the data */
+ temp_buffer[1] = value;
+ return twl4030_i2c_write(mod_no, temp_buffer, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_write_u8);
+
+/**
+ * twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030
+ * @mod_no: module number
+ * @value: the value read 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl4030_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
+{
+ return twl4030_i2c_read(mod_no, value, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_read_u8);
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * NOTE: We know the first 8 IRQs after pdata->base_irq are
+ * for the PIH, and the next are for the PWR_INT SIH, since
+ * that's how twl_init_irq() sets things up.
+ */
+
+static int add_children(struct twl4030_platform_data *pdata)
+{
+ struct platform_device *pdev = NULL;
+ struct twl4030_client *twl = NULL;
+ int status = 0;
+
+ if (twl_has_bci() && pdata->bci) {
+ twl = &twl4030_modules[3];
+
+ pdev = platform_device_alloc("twl4030_bci", -1);
+ if (!pdev) {
+ pr_debug("%s: can't alloc bci dev\n", DRIVER_NAME);
+ status = -ENOMEM;
+ goto err;
+ }
+
+ if (status == 0) {
+ pdev->dev.parent = &twl->client->dev;
+ status = platform_device_add_data(pdev, pdata->bci,
+ sizeof(*pdata->bci));
+ if (status < 0) {
+ dev_dbg(&twl->client->dev,
+ "can't add bci data, %d\n",
+ status);
+ goto err;
+ }
+ }
+
+ if (status == 0) {
+ struct resource r = {
+ .start = pdata->irq_base + 8 + 1,
+ .flags = IORESOURCE_IRQ,
+ };
+
+ status = platform_device_add_resources(pdev, &r, 1);
+ }
+
+ if (status == 0)
+ status = platform_device_add(pdev);
+
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_dbg(&twl->client->dev,
+ "can't create bci dev, %d\n",
+ status);
+ goto err;
+ }
+ }
+
+ if (twl_has_gpio() && pdata->gpio) {
+ twl = &twl4030_modules[1];
+
+ pdev = platform_device_alloc("twl4030_gpio", -1);
+ if (!pdev) {
+ pr_debug("%s: can't alloc gpio dev\n", DRIVER_NAME);
+ status = -ENOMEM;
+ goto err;
+ }
+
+ /* more driver model init */
+ if (status == 0) {
+ pdev->dev.parent = &twl->client->dev;
+ /* device_init_wakeup(&pdev->dev, 1); */
+
+ status = platform_device_add_data(pdev, pdata->gpio,
+ sizeof(*pdata->gpio));
+ if (status < 0) {
+ dev_dbg(&twl->client->dev,
+ "can't add gpio data, %d\n",
+ status);
+ goto err;
+ }
+ }
+
+ /* GPIO module IRQ */
+ if (status == 0) {
+ struct resource r = {
+ .start = pdata->irq_base + 0,
+ .flags = IORESOURCE_IRQ,
+ };
+
+ status = platform_device_add_resources(pdev, &r, 1);
+ }
+
+ if (status == 0)
+ status = platform_device_add(pdev);
+
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_dbg(&twl->client->dev,
+ "can't create gpio dev, %d\n",
+ status);
+ goto err;
+ }
+ }
+
+ if (twl_has_keypad() && pdata->keypad) {
+ pdev = platform_device_alloc("twl4030_keypad", -1);
+ if (pdev) {
+ twl = &twl4030_modules[2];
+ pdev->dev.parent = &twl->client->dev;
+ device_init_wakeup(&pdev->dev, 1);
+ status = platform_device_add_data(pdev, pdata->keypad,
+ sizeof(*pdata->keypad));
+ if (status < 0) {
+ dev_dbg(&twl->client->dev,
+ "can't add keypad data, %d\n",
+ status);
+ platform_device_put(pdev);
+ goto err;
+ }
+ status = platform_device_add(pdev);
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_dbg(&twl->client->dev,
+ "can't create keypad dev, %d\n",
+ status);
+ goto err;
+ }
+ } else {
+ pr_debug("%s: can't alloc keypad dev\n", DRIVER_NAME);
+ status = -ENOMEM;
+ goto err;
+ }
+ }
+
+ if (twl_has_madc() && pdata->madc) {
+ pdev = platform_device_alloc("twl4030_madc", -1);
+ if (pdev) {
+ twl = &twl4030_modules[2];
+ pdev->dev.parent = &twl->client->dev;
+ device_init_wakeup(&pdev->dev, 1);
+ status = platform_device_add_data(pdev, pdata->madc,
+ sizeof(*pdata->madc));
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_dbg(&twl->client->dev,
+ "can't add madc data, %d\n",
+ status);
+ goto err;
+ }
+ status = platform_device_add(pdev);
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_dbg(&twl->client->dev,
+ "can't create madc dev, %d\n",
+ status);
+ goto err;
+ }
+ } else {
+ pr_debug("%s: can't alloc madc dev\n", DRIVER_NAME);
+ status = -ENOMEM;
+ goto err;
+ }
+ }
+
+ if (twl_has_rtc()) {
+ twl = &twl4030_modules[3];
+
+ pdev = platform_device_alloc("twl4030_rtc", -1);
+ if (!pdev) {
+ pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME);
+ status = -ENOMEM;
+ } else {
+ pdev->dev.parent = &twl->client->dev;
+ device_init_wakeup(&pdev->dev, 1);
+ }
+
+ /*
+ * REVISIT platform_data here currently might use of
+ * "msecure" line ... but for now we just expect board
+ * setup to tell the chip "we are secure" at all times.
+ * Eventually, Linux might become more aware of such
+ * HW security concerns, and "least privilege".
+ */
+
+ /* RTC module IRQ */
+ if (status == 0) {
+ struct resource r = {
+ .start = pdata->irq_base + 8 + 3,
+ .flags = IORESOURCE_IRQ,
+ };
+
+ status = platform_device_add_resources(pdev, &r, 1);
+ }
+
+ if (status == 0)
+ status = platform_device_add(pdev);
+
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_dbg(&twl->client->dev,
+ "can't create rtc dev, %d\n",
+ status);
+ goto err;
+ }
+ }
+
+ if (twl_has_usb() && pdata->usb) {
+ twl = &twl4030_modules[0];
+
+ pdev = platform_device_alloc("twl4030_usb", -1);
+ if (!pdev) {
+ pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME);
+ status = -ENOMEM;
+ goto err;
+ }
+
+ if (status == 0) {
+ pdev->dev.parent = &twl->client->dev;
+ device_init_wakeup(&pdev->dev, 1);
+ status = platform_device_add_data(pdev, pdata->usb,
+ sizeof(*pdata->usb));
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_dbg(&twl->client->dev,
+ "can't add usb data, %d\n",
+ status);
+ goto err;
+ }
+ }
+
+ if (status == 0) {
+ struct resource r = {
+ .start = pdata->irq_base + 8 + 2,
+ .flags = IORESOURCE_IRQ,
+ };
+
+ status = platform_device_add_resources(pdev, &r, 1);
+ }
+
+ if (status == 0)
+ status = platform_device_add(pdev);
+
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_dbg(&twl->client->dev,
+ "can't create usb dev, %d\n",
+ status);
+ }
+ }
+
+err:
+ if (status)
+ pr_err("failed to add twl4030's children (status %d)\n", status);
+ return status;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * These three functions initialize the on-chip clock framework,
+ * letting it generate the right frequencies for USB, MADC, and
+ * other purposes.
+ */
+static inline int __init protect_pm_master(void)
+{
+ int e = 0;
+
+ e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK,
+ R_PROTECT_KEY);
+ return e;
+}
+
+static inline int __init unprotect_pm_master(void)
+{
+ int e = 0;
+
+ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1,
+ R_PROTECT_KEY);
+ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2,
+ R_PROTECT_KEY);
+ return e;
+}
+
+static void __init clocks_init(void)
+{
+ int e = 0;
+ struct clk *osc;
+ u32 rate;
+ u8 ctrl = HFCLK_FREQ_26_MHZ;
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+ if (cpu_is_omap2430())
+ osc = clk_get(NULL, "osc_ck");
+ else
+ osc = clk_get(NULL, "osc_sys_ck");
+#else
+ /* REVISIT for non-OMAP systems, pass the clock rate from
+ * board init code, using platform_data.
+ */
+ osc = ERR_PTR(-EIO);
+#endif
+ if (IS_ERR(osc)) {
+ printk(KERN_WARNING "Skipping twl4030 internal clock init and "
+ "using bootloader value (unknown osc rate)\n");
+ return;
+ }
+
+ rate = clk_get_rate(osc);
+ clk_put(osc);
+
+ switch (rate) {
+ case 19200000:
+ ctrl = HFCLK_FREQ_19p2_MHZ;
+ break;
+ case 26000000:
+ ctrl = HFCLK_FREQ_26_MHZ;
+ break;
+ case 38400000:
+ ctrl = HFCLK_FREQ_38p4_MHZ;
+ break;
+ }
+
+ ctrl |= HIGH_PERF_SQ;
+ e |= unprotect_pm_master();
+ /* effect->MADC+USB ck en */
+ e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
+ e |= protect_pm_master();
+
+ if (e < 0)
+ pr_err("%s: clock init err [%d]\n", DRIVER_NAME, e);
+}
+
+/*----------------------------------------------------------------------*/
+
+int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+int twl_exit_irq(void);
+
+static int twl4030_remove(struct i2c_client *client)
+{
+ unsigned i;
+ int status;
+
+ status = twl_exit_irq();
+ if (status < 0)
+ return status;
+
+ for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
+ struct twl4030_client *twl = &twl4030_modules[i];
+
+ if (twl->client && twl->client != client)
+ i2c_unregister_device(twl->client);
+ twl4030_modules[i].client = NULL;
+ }
+ inuse = false;
+ return 0;
+}
+
+/* NOTE: this driver only handles a single twl4030/tps659x0 chip */
+static int
+twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ int status;
+ unsigned i;
+ struct twl4030_platform_data *pdata = client->dev.platform_data;
+
+ if (!pdata) {
+ dev_dbg(&client->dev, "no platform data?\n");
+ return -EINVAL;
+ }
+
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+ dev_dbg(&client->dev, "can't talk I2C?\n");
+ return -EIO;
+ }
+
+ if (inuse) {
+ dev_dbg(&client->dev, "driver is already in use\n");
+ return -EBUSY;
+ }
+
+ for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
+ struct twl4030_client *twl = &twl4030_modules[i];
+
+ twl->address = client->addr + i;
+ if (i == 0)
+ twl->client = client;
+ else {
+ twl->client = i2c_new_dummy(client->adapter,
+ twl->address);
+ if (!twl->client) {
+ dev_err(&twl->client->dev,
+ "can't attach client %d\n", i);
+ status = -ENOMEM;
+ goto fail;
+ }
+ strlcpy(twl->client->name, id->name,
+ sizeof(twl->client->name));
+ }
+ mutex_init(&twl->xfer_lock);
+ }
+ inuse = true;
+
+ /* setup clock framework */
+ clocks_init();
+
+ /* Maybe init the T2 Interrupt subsystem */
+ if (client->irq
+ && pdata->irq_base
+ && pdata->irq_end > pdata->irq_base) {
+ status = twl_init_irq(client->irq, pdata->irq_base, pdata->irq_end);
+ if (status < 0)
+ goto fail;
+ }
+
+ status = add_children(pdata);
+fail:
+ if (status < 0)
+ twl4030_remove(client);
+ return status;
+}
+
+static const struct i2c_device_id twl4030_ids[] = {
+ { "twl4030", 0 }, /* "Triton 2" */
+ { "tps65950", 0 }, /* catalog version of twl4030 */
+ { "tps65930", 0 }, /* fewer LDOs and DACs; no charger */
+ { "tps65920", 0 }, /* fewer LDOs; no codec or charger */
+ { "twl5030", 0 }, /* T2 updated */
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(i2c, twl4030_ids);
+
+/* One Client Driver , 4 Clients */
+static struct i2c_driver twl4030_driver = {
+ .driver.name = DRIVER_NAME,
+ .id_table = twl4030_ids,
+ .probe = twl4030_probe,
+ .remove = twl4030_remove,
+};
+
+static int __init twl4030_init(void)
+{
+ return i2c_add_driver(&twl4030_driver);
+}
+subsys_initcall(twl4030_init);
+
+static void __exit twl4030_exit(void)
+{
+ i2c_del_driver(&twl4030_driver);
+}
+module_exit(twl4030_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("I2C Core interface for TWL4030");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
new file mode 100644
index 00000000000..fae868a8d49
--- /dev/null
+++ b/drivers/mfd/twl4030-irq.c
@@ -0,0 +1,743 @@
+/*
+ * twl4030-irq.c - TWL4030/TPS659x0 irq support
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Modifications to defer interrupt handling to a kernel thread:
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Code cleanup and modifications to IRQ handler.
+ * by syed khasim <x0khasim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * TWL4030 IRQ handling has two stages in hardware, and thus in software.
+ * The Primary Interrupt Handler (PIH) stage exposes status bits saying
+ * which Secondary Interrupt Handler (SIH) stage is raising an interrupt.
+ * SIH modules are more traditional IRQ components, which support per-IRQ
+ * enable/disable and trigger controls; they do most of the work.
+ *
+ * These chips are designed to support IRQ handling from two different
+ * I2C masters. Each has a dedicated IRQ line, and dedicated IRQ status
+ * and mask registers in the PIH and SIH modules.
+ *
+ * We set up IRQs starting at a platform-specified base, always starting
+ * with PIH and the SIH for PWR_INT and then usually adding GPIO:
+ * base + 0 .. base + 7 PIH
+ * base + 8 .. base + 15 SIH for PWR_INT
+ * base + 16 .. base + 33 SIH for GPIO
+ */
+
+/* PIH register offsets */
+#define REG_PIH_ISR_P1 0x01
+#define REG_PIH_ISR_P2 0x02
+#define REG_PIH_SIR 0x03 /* for testing */
+
+
+/* Linux could (eventually) use either IRQ line */
+static int irq_line;
+
+struct sih {
+ char name[8];
+ u8 module; /* module id */
+ u8 control_offset; /* for SIH_CTRL */
+ bool set_cor;
+
+ u8 bits; /* valid in isr/imr */
+ u8 bytes_ixr; /* bytelen of ISR/IMR/SIR */
+
+ u8 edr_offset;
+ u8 bytes_edr; /* bytelen of EDR */
+
+ /* SIR ignored -- set interrupt, for testing only */
+ struct irq_data {
+ u8 isr_offset;
+ u8 imr_offset;
+ } mask[2];
+ /* + 2 bytes padding */
+};
+
+#define SIH_INITIALIZER(modname, nbits) \
+ .module = TWL4030_MODULE_ ## modname, \
+ .control_offset = TWL4030_ ## modname ## _SIH_CTRL, \
+ .bits = nbits, \
+ .bytes_ixr = DIV_ROUND_UP(nbits, 8), \
+ .edr_offset = TWL4030_ ## modname ## _EDR, \
+ .bytes_edr = DIV_ROUND_UP((2*(nbits)), 8), \
+ .mask = { { \
+ .isr_offset = TWL4030_ ## modname ## _ISR1, \
+ .imr_offset = TWL4030_ ## modname ## _IMR1, \
+ }, \
+ { \
+ .isr_offset = TWL4030_ ## modname ## _ISR2, \
+ .imr_offset = TWL4030_ ## modname ## _IMR2, \
+ }, },
+
+/* register naming policies are inconsistent ... */
+#define TWL4030_INT_PWR_EDR TWL4030_INT_PWR_EDR1
+#define TWL4030_MODULE_KEYPAD_KEYP TWL4030_MODULE_KEYPAD
+#define TWL4030_MODULE_INT_PWR TWL4030_MODULE_INT
+
+
+/* Order in this table matches order in PIH_ISR. That is,
+ * BIT(n) in PIH_ISR is sih_modules[n].
+ */
+static const struct sih sih_modules[6] = {
+ [0] = {
+ .name = "gpio",
+ .module = TWL4030_MODULE_GPIO,
+ .control_offset = REG_GPIO_SIH_CTRL,
+ .set_cor = true,
+ .bits = TWL4030_GPIO_MAX,
+ .bytes_ixr = 3,
+ /* Note: *all* of these IRQs default to no-trigger */
+ .edr_offset = REG_GPIO_EDR1,
+ .bytes_edr = 5,
+ .mask = { {
+ .isr_offset = REG_GPIO_ISR1A,
+ .imr_offset = REG_GPIO_IMR1A,
+ }, {
+ .isr_offset = REG_GPIO_ISR1B,
+ .imr_offset = REG_GPIO_IMR1B,
+ }, },
+ },
+ [1] = {
+ .name = "keypad",
+ .set_cor = true,
+ SIH_INITIALIZER(KEYPAD_KEYP, 4)
+ },
+ [2] = {
+ .name = "bci",
+ .module = TWL4030_MODULE_INTERRUPTS,
+ .control_offset = TWL4030_INTERRUPTS_BCISIHCTRL,
+ .bits = 12,
+ .bytes_ixr = 2,
+ .edr_offset = TWL4030_INTERRUPTS_BCIEDR1,
+ /* Note: most of these IRQs default to no-trigger */
+ .bytes_edr = 3,
+ .mask = { {
+ .isr_offset = TWL4030_INTERRUPTS_BCIISR1A,
+ .imr_offset = TWL4030_INTERRUPTS_BCIIMR1A,
+ }, {
+ .isr_offset = TWL4030_INTERRUPTS_BCIISR1B,
+ .imr_offset = TWL4030_INTERRUPTS_BCIIMR1B,
+ }, },
+ },
+ [3] = {
+ .name = "madc",
+ SIH_INITIALIZER(MADC, 4)
+ },
+ [4] = {
+ /* USB doesn't use the same SIH organization */
+ .name = "usb",
+ },
+ [5] = {
+ .name = "power",
+ .set_cor = true,
+ SIH_INITIALIZER(INT_PWR, 8)
+ },
+ /* there are no SIH modules #6 or #7 ... */
+};
+
+#undef TWL4030_MODULE_KEYPAD_KEYP
+#undef TWL4030_MODULE_INT_PWR
+#undef TWL4030_INT_PWR_EDR
+
+/*----------------------------------------------------------------------*/
+
+static unsigned twl4030_irq_base;
+
+static struct completion irq_event;
+
+/*
+ * This thread processes interrupts reported by the Primary Interrupt Handler.
+ */
+static int twl4030_irq_thread(void *data)
+{
+ long irq = (long)data;
+ irq_desc_t *desc = irq_desc + irq;
+ static unsigned i2c_errors;
+ const static unsigned max_i2c_errors = 100;
+
+ current->flags |= PF_NOFREEZE;
+
+ while (!kthread_should_stop()) {
+ int ret;
+ int module_irq;
+ u8 pih_isr;
+
+ /* Wait for IRQ, then read PIH irq status (also blocking) */
+ wait_for_completion_interruptible(&irq_event);
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
+ REG_PIH_ISR_P1);
+ if (ret) {
+ pr_warning("twl4030: I2C error %d reading PIH ISR\n",
+ ret);
+ if (++i2c_errors >= max_i2c_errors) {
+ printk(KERN_ERR "Maximum I2C error count"
+ " exceeded. Terminating %s.\n",
+ __func__);
+ break;
+ }
+ complete(&irq_event);
+ continue;
+ }
+
+ /* these handlers deal with the relevant SIH irq status */
+ local_irq_disable();
+ for (module_irq = twl4030_irq_base;
+ pih_isr;
+ pih_isr >>= 1, module_irq++) {
+ if (pih_isr & 0x1) {
+ irq_desc_t *d = irq_desc + module_irq;
+
+ /* These can't be masked ... always warn
+ * if we get any surprises.
+ */
+ if (d->status & IRQ_DISABLED)
+ note_interrupt(module_irq, d,
+ IRQ_NONE);
+ else
+ d->handle_irq(module_irq, d);
+ }
+ }
+ local_irq_enable();
+
+ desc->chip->unmask(irq);
+ }
+
+ return 0;
+}
+
+/*
+ * handle_twl4030_pih() is the desc->handle method for the twl4030 interrupt.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * Now we need to query the interrupt controller in the twl4030 to determine
+ * which module is generating the interrupt request. However, we can't do i2c
+ * transactions in interrupt context, so we must defer that work to a kernel
+ * thread. All we do here is acknowledge and mask the interrupt and wakeup
+ * the kernel thread.
+ */
+static void handle_twl4030_pih(unsigned int irq, irq_desc_t *desc)
+{
+ /* Acknowledge, clear *AND* mask the interrupt... */
+ desc->chip->ack(irq);
+ complete(&irq_event);
+}
+
+static struct task_struct *start_twl4030_irq_thread(long irq)
+{
+ struct task_struct *thread;
+
+ init_completion(&irq_event);
+ thread = kthread_run(twl4030_irq_thread, (void *)irq, "twl4030-irq");
+ if (!thread)
+ pr_err("twl4030: could not create irq %ld thread!\n", irq);
+
+ return thread;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * twl4030_init_sih_modules() ... start from a known state where no
+ * IRQs will be coming in, and where we can quickly enable them then
+ * handle them as they arrive. Mask all IRQs: maybe init SIH_CTRL.
+ *
+ * NOTE: we don't touch EDR registers here; they stay with hardware
+ * defaults or whatever the last value was. Note that when both EDR
+ * bits for an IRQ are clear, that's as if its IMR bit is set...
+ */
+static int twl4030_init_sih_modules(unsigned line)
+{
+ const struct sih *sih;
+ u8 buf[4];
+ int i;
+ int status;
+
+ /* line 0 == int1_n signal; line 1 == int2_n signal */
+ if (line > 1)
+ return -EINVAL;
+
+ irq_line = line;
+
+ /* disable all interrupts on our line */
+ memset(buf, 0xff, sizeof buf);
+ sih = sih_modules;
+ for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) {
+
+ /* skip USB -- it's funky */
+ if (!sih->bytes_ixr)
+ continue;
+
+ status = twl4030_i2c_write(sih->module, buf,
+ sih->mask[line].imr_offset, sih->bytes_ixr);
+ if (status < 0)
+ pr_err("twl4030: err %d initializing %s %s\n",
+ status, sih->name, "IMR");
+
+ /* Maybe disable "exclusive" mode; buffer second pending irq;
+ * set Clear-On-Read (COR) bit.
+ *
+ * NOTE that sometimes COR polarity is documented as being
+ * inverted: for MADC and BCI, COR=1 means "clear on write".
+ * And for PWR_INT it's not documented...
+ */
+ if (sih->set_cor) {
+ status = twl4030_i2c_write_u8(sih->module,
+ TWL4030_SIH_CTRL_COR_MASK,
+ sih->control_offset);
+ if (status < 0)
+ pr_err("twl4030: err %d initializing %s %s\n",
+ status, sih->name, "SIH_CTRL");
+ }
+ }
+
+ sih = sih_modules;
+ for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) {
+ u8 rxbuf[4];
+ int j;
+
+ /* skip USB */
+ if (!sih->bytes_ixr)
+ continue;
+
+ /* Clear pending interrupt status. Either the read was
+ * enough, or we need to write those bits. Repeat, in
+ * case an IRQ is pending (PENDDIS=0) ... that's not
+ * uncommon with PWR_INT.PWRON.
+ */
+ for (j = 0; j < 2; j++) {
+ status = twl4030_i2c_read(sih->module, rxbuf,
+ sih->mask[line].isr_offset, sih->bytes_ixr);
+ if (status < 0)
+ pr_err("twl4030: err %d initializing %s %s\n",
+ status, sih->name, "ISR");
+
+ if (!sih->set_cor)
+ status = twl4030_i2c_write(sih->module, buf,
+ sih->mask[line].isr_offset,
+ sih->bytes_ixr);
+ /* else COR=1 means read sufficed.
+ * (for most SIH modules...)
+ */
+ }
+ }
+
+ return 0;
+}
+
+static inline void activate_irq(int irq)
+{
+#ifdef CONFIG_ARM
+ /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+ * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
+ */
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ /* same effect on other architectures */
+ set_irq_noprobe(irq);
+#endif
+}
+
+/*----------------------------------------------------------------------*/
+
+static DEFINE_SPINLOCK(sih_agent_lock);
+
+static struct workqueue_struct *wq;
+
+struct sih_agent {
+ int irq_base;
+ const struct sih *sih;
+
+ u32 imr;
+ bool imr_change_pending;
+ struct work_struct mask_work;
+
+ u32 edge_change;
+ struct work_struct edge_work;
+};
+
+static void twl4030_sih_do_mask(struct work_struct *work)
+{
+ struct sih_agent *agent;
+ const struct sih *sih;
+ union {
+ u8 bytes[4];
+ u32 word;
+ } imr;
+ int status;
+
+ agent = container_of(work, struct sih_agent, mask_work);
+
+ /* see what work we have */
+ spin_lock_irq(&sih_agent_lock);
+ if (agent->imr_change_pending) {
+ sih = agent->sih;
+ /* byte[0] gets overwritten as we write ... */
+ imr.word = cpu_to_le32(agent->imr << 8);
+ agent->imr_change_pending = false;
+ } else
+ sih = NULL;
+ spin_unlock_irq(&sih_agent_lock);
+ if (!sih)
+ return;
+
+ /* write the whole mask ... simpler than subsetting it */
+ status = twl4030_i2c_write(sih->module, imr.bytes,
+ sih->mask[irq_line].imr_offset, sih->bytes_ixr);
+ if (status)
+ pr_err("twl4030: %s, %s --> %d\n", __func__,
+ "write", status);
+}
+
+static void twl4030_sih_do_edge(struct work_struct *work)
+{
+ struct sih_agent *agent;
+ const struct sih *sih;
+ u8 bytes[6];
+ u32 edge_change;
+ int status;
+
+ agent = container_of(work, struct sih_agent, edge_work);
+
+ /* see what work we have */
+ spin_lock_irq(&sih_agent_lock);
+ edge_change = agent->edge_change;
+ agent->edge_change = 0;;
+ sih = edge_change ? agent->sih : NULL;
+ spin_unlock_irq(&sih_agent_lock);
+ if (!sih)
+ return;
+
+ /* Read, reserving first byte for write scratch. Yes, this
+ * could be cached for some speedup ... but be careful about
+ * any processor on the other IRQ line, EDR registers are
+ * shared.
+ */
+ status = twl4030_i2c_read(sih->module, bytes + 1,
+ sih->edr_offset, sih->bytes_edr);
+ if (status) {
+ pr_err("twl4030: %s, %s --> %d\n", __func__,
+ "read", status);
+ return;
+ }
+
+ /* Modify only the bits we know must change */
+ while (edge_change) {
+ int i = fls(edge_change) - 1;
+ struct irq_desc *d = irq_desc + i + agent->irq_base;
+ int byte = 1 + (i >> 2);
+ int off = (i & 0x3) * 2;
+
+ bytes[byte] &= ~(0x03 << off);
+
+ spin_lock_irq(&d->lock);
+ if (d->status & IRQ_TYPE_EDGE_RISING)
+ bytes[byte] |= BIT(off + 1);
+ if (d->status & IRQ_TYPE_EDGE_FALLING)
+ bytes[byte] |= BIT(off + 0);
+ spin_unlock_irq(&d->lock);
+
+ edge_change &= ~BIT(i);
+ }
+
+ /* Write */
+ status = twl4030_i2c_write(sih->module, bytes,
+ sih->edr_offset, sih->bytes_edr);
+ if (status)
+ pr_err("twl4030: %s, %s --> %d\n", __func__,
+ "write", status);
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * All irq_chip methods get issued from code holding irq_desc[irq].lock,
+ * which can't perform the underlying I2C operations (because they sleep).
+ * So we must hand them off to a thread (workqueue) and cope with asynch
+ * completion, potentially including some re-ordering, of these requests.
+ */
+
+static void twl4030_sih_mask(unsigned irq)
+{
+ struct sih_agent *sih = get_irq_chip_data(irq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sih_agent_lock, flags);
+ sih->imr |= BIT(irq - sih->irq_base);
+ sih->imr_change_pending = true;
+ queue_work(wq, &sih->mask_work);
+ spin_unlock_irqrestore(&sih_agent_lock, flags);
+}
+
+static void twl4030_sih_unmask(unsigned irq)
+{
+ struct sih_agent *sih = get_irq_chip_data(irq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sih_agent_lock, flags);
+ sih->imr &= ~BIT(irq - sih->irq_base);
+ sih->imr_change_pending = true;
+ queue_work(wq, &sih->mask_work);
+ spin_unlock_irqrestore(&sih_agent_lock, flags);
+}
+
+static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
+{
+ struct sih_agent *sih = get_irq_chip_data(irq);
+ struct irq_desc *desc = irq_desc + irq;
+ unsigned long flags;
+
+ if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+ return -EINVAL;
+
+ spin_lock_irqsave(&sih_agent_lock, flags);
+ if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) {
+ desc->status &= ~IRQ_TYPE_SENSE_MASK;
+ desc->status |= trigger;
+ sih->edge_change |= BIT(irq - sih->irq_base);
+ queue_work(wq, &sih->edge_work);
+ }
+ spin_unlock_irqrestore(&sih_agent_lock, flags);
+ return 0;
+}
+
+static struct irq_chip twl4030_sih_irq_chip = {
+ .name = "twl4030",
+ .mask = twl4030_sih_mask,
+ .unmask = twl4030_sih_unmask,
+ .set_type = twl4030_sih_set_type,
+};
+
+/*----------------------------------------------------------------------*/
+
+static inline int sih_read_isr(const struct sih *sih)
+{
+ int status;
+ union {
+ u8 bytes[4];
+ u32 word;
+ } isr;
+
+ /* FIXME need retry-on-error ... */
+
+ isr.word = 0;
+ status = twl4030_i2c_read(sih->module, isr.bytes,
+ sih->mask[irq_line].isr_offset, sih->bytes_ixr);
+
+ return (status < 0) ? status : le32_to_cpu(isr.word);
+}
+
+/*
+ * Generic handler for SIH interrupts ... we "know" this is called
+ * in task context, with IRQs enabled.
+ */
+static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc)
+{
+ struct sih_agent *agent = get_irq_data(irq);
+ const struct sih *sih = agent->sih;
+ int isr;
+
+ /* reading ISR acks the IRQs, using clear-on-read mode */
+ local_irq_enable();
+ isr = sih_read_isr(sih);
+ local_irq_disable();
+
+ if (isr < 0) {
+ pr_err("twl4030: %s SIH, read ISR error %d\n",
+ sih->name, isr);
+ /* REVISIT: recover; eventually mask it all, etc */
+ return;
+ }
+
+ while (isr) {
+ irq = fls(isr);
+ irq--;
+ isr &= ~BIT(irq);
+
+ if (irq < sih->bits)
+ generic_handle_irq(agent->irq_base + irq);
+ else
+ pr_err("twl4030: %s SIH, invalid ISR bit %d\n",
+ sih->name, irq);
+ }
+}
+
+static unsigned twl4030_irq_next;
+
+/* returns the first IRQ used by this SIH bank,
+ * or negative errno
+ */
+int twl4030_sih_setup(int module)
+{
+ int sih_mod;
+ const struct sih *sih = NULL;
+ struct sih_agent *agent;
+ int i, irq;
+ int status = -EINVAL;
+ unsigned irq_base = twl4030_irq_next;
+
+ /* only support modules with standard clear-on-read for now */
+ for (sih_mod = 0, sih = sih_modules;
+ sih_mod < ARRAY_SIZE(sih_modules);
+ sih_mod++, sih++) {
+ if (sih->module == module && sih->set_cor) {
+ if (!WARN((irq_base + sih->bits) > NR_IRQS,
+ "irq %d for %s too big\n",
+ irq_base + sih->bits,
+ sih->name))
+ status = 0;
+ break;
+ }
+ }
+ if (status < 0)
+ return status;
+
+ agent = kzalloc(sizeof *agent, GFP_KERNEL);
+ if (!agent)
+ return -ENOMEM;
+
+ status = 0;
+
+ agent->irq_base = irq_base;
+ agent->sih = sih;
+ agent->imr = ~0;
+ INIT_WORK(&agent->mask_work, twl4030_sih_do_mask);
+ INIT_WORK(&agent->edge_work, twl4030_sih_do_edge);
+
+ for (i = 0; i < sih->bits; i++) {
+ irq = irq_base + i;
+
+ set_irq_chip_and_handler(irq, &twl4030_sih_irq_chip,
+ handle_edge_irq);
+ set_irq_chip_data(irq, agent);
+ activate_irq(irq);
+ }
+
+ status = irq_base;
+ twl4030_irq_next += i;
+
+ /* replace generic PIH handler (handle_simple_irq) */
+ irq = sih_mod + twl4030_irq_base;
+ set_irq_data(irq, agent);
+ set_irq_chained_handler(irq, handle_twl4030_sih);
+
+ pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
+ irq, irq_base, twl4030_irq_next - 1);
+
+ return status;
+}
+
+/* FIXME need a call to reverse twl4030_sih_setup() ... */
+
+
+/*----------------------------------------------------------------------*/
+
+/* FIXME pass in which interrupt line we'll use ... */
+#define twl_irq_line 0
+
+int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+{
+ static struct irq_chip twl4030_irq_chip;
+
+ int status;
+ int i;
+ struct task_struct *task;
+
+ /*
+ * Mask and clear all TWL4030 interrupts since initially we do
+ * not have any TWL4030 module interrupt handlers present
+ */
+ status = twl4030_init_sih_modules(twl_irq_line);
+ if (status < 0)
+ return status;
+
+ wq = create_singlethread_workqueue("twl4030-irqchip");
+ if (!wq) {
+ pr_err("twl4030: workqueue FAIL\n");
+ return -ESRCH;
+ }
+
+ twl4030_irq_base = irq_base;
+
+ /* install an irq handler for each of the SIH modules;
+ * clone dummy irq_chip since PIH can't *do* anything
+ */
+ twl4030_irq_chip = dummy_irq_chip;
+ twl4030_irq_chip.name = "twl4030";
+
+ twl4030_sih_irq_chip.ack = dummy_irq_chip.ack;
+
+ for (i = irq_base; i < irq_end; i++) {
+ set_irq_chip_and_handler(i, &twl4030_irq_chip,
+ handle_simple_irq);
+ activate_irq(i);
+ }
+ twl4030_irq_next = i;
+ pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
+ irq_num, irq_base, twl4030_irq_next - 1);
+
+ /* ... and the PWR_INT module ... */
+ status = twl4030_sih_setup(TWL4030_MODULE_INT);
+ if (status < 0) {
+ pr_err("twl4030: sih_setup PWR INT --> %d\n", status);
+ goto fail;
+ }
+
+ /* install an irq handler to demultiplex the TWL4030 interrupt */
+ task = start_twl4030_irq_thread(irq_num);
+ if (!task) {
+ pr_err("twl4030: irq thread FAIL\n");
+ status = -ESRCH;
+ goto fail;
+ }
+
+ set_irq_data(irq_num, task);
+ set_irq_chained_handler(irq_num, handle_twl4030_pih);
+
+ return status;
+
+fail:
+ for (i = irq_base; i < irq_end; i++)
+ set_irq_chip_and_handler(i, NULL, NULL);
+ destroy_workqueue(wq);
+ wq = NULL;
+ return status;
+}
+
+int twl_exit_irq(void)
+{
+ /* FIXME undo twl_init_irq() */
+ if (twl4030_irq_base) {
+ pr_err("twl4030: can't yet clean up IRQs?\n");
+ return -ENOSYS;
+ }
+ return 0;
+}
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index 25a7a5d08bc..0d47fb9e4b3 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -183,6 +183,9 @@ static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src)
(wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable)
| src[i - reg];
+ /* Don't store volatile bits */
+ wm8350->reg_cache[i] &= ~wm8350_reg_io_map[i].vol;
+
src[i - reg] = cpu_to_be16(src[i - reg]);
}
@@ -1120,6 +1123,7 @@ static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
}
value = be16_to_cpu(value);
value &= wm8350_reg_io_map[i].readable;
+ value &= ~wm8350_reg_io_map[i].vol;
wm8350->reg_cache[i] = value;
} else
wm8350->reg_cache[i] = reg_map[i];
@@ -1128,7 +1132,6 @@ static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
out:
return ret;
}
-EXPORT_SYMBOL_GPL(wm8350_create_cache);
/*
* Register a client device. This is non-fatal since there is no need to
@@ -1217,7 +1220,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
mutex_init(&wm8350->irq_mutex);
INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
- if (irq != NO_IRQ) {
+ if (irq) {
ret = request_irq(irq, wm8350_irq, 0,
"wm8350", wm8350);
if (ret != 0) {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index efd3aa08b88..9494400e8fd 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -145,6 +145,7 @@ config ACER_WMI
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
@@ -245,6 +246,17 @@ config MSI_LAPTOP
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
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c6c13f60b45..909e2468cdc 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -23,6 +23,7 @@ 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
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index d8b0d326e45..0532a2de2ce 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/misc/acer-wmi.c
@@ -33,6 +33,8 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/i8042.h>
+#include <linux/rfkill.h>
+#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <acpi/acpi_drivers.h>
@@ -123,21 +125,15 @@ enum interface_flags {
static int max_brightness = 0xF;
-static int wireless = -1;
-static int bluetooth = -1;
static int mailled = -1;
static int brightness = -1;
static int threeg = -1;
static int force_series;
module_param(mailled, int, 0444);
-module_param(wireless, int, 0444);
-module_param(bluetooth, int, 0444);
module_param(brightness, int, 0444);
module_param(threeg, int, 0444);
module_param(force_series, int, 0444);
-MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
-MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
@@ -145,8 +141,6 @@ MODULE_PARM_DESC(force_series, "Force a different laptop series");
struct acer_data {
int mailled;
- int wireless;
- int bluetooth;
int threeg;
int brightness;
};
@@ -157,6 +151,9 @@ struct acer_debug {
u32 wmid_devices;
};
+static struct rfkill *wireless_rfkill;
+static struct rfkill *bluetooth_rfkill;
+
/* Each low-level interface must define at least some of the following */
struct wmi_interface {
/* The WMI device type */
@@ -476,7 +473,7 @@ struct wmi_interface *iface)
}
break;
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
return AE_OK;
}
@@ -514,7 +511,7 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
break;
}
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
/* Actually do the set */
@@ -689,7 +686,7 @@ struct wmi_interface *iface)
return 0;
}
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
status = WMI_execute_u32(method_id, 0, &result);
@@ -735,7 +732,7 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
}
break;
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
return WMI_execute_u32(method_id, (u32)value, NULL);
}
@@ -785,7 +782,7 @@ static struct wmi_interface wmid_interface = {
static acpi_status get_u32(u32 *value, u32 cap)
{
- acpi_status status = AE_BAD_ADDRESS;
+ acpi_status status = AE_ERROR;
switch (interface->type) {
case ACER_AMW0:
@@ -846,8 +843,6 @@ static void __init acer_commandline_init(void)
* capability isn't available on the given interface
*/
set_u32(mailled, ACER_CAP_MAILLED);
- set_u32(wireless, ACER_CAP_WIRELESS);
- set_u32(bluetooth, ACER_CAP_BLUETOOTH);
set_u32(threeg, ACER_CAP_THREEG);
set_u32(brightness, ACER_CAP_BRIGHTNESS);
}
@@ -933,40 +928,135 @@ static void acer_backlight_exit(void)
}
/*
- * Read/ write bool sysfs macro
+ * Rfkill devices
*/
-#define show_set_bool(value, cap) \
-static ssize_t \
-show_bool_##value(struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- u32 result; \
- acpi_status status = get_u32(&result, cap); \
- if (ACPI_SUCCESS(status)) \
- return sprintf(buf, "%u\n", result); \
- return sprintf(buf, "Read error\n"); \
-} \
-\
-static ssize_t \
-set_bool_##value(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- u32 tmp = simple_strtoul(buf, NULL, 10); \
- acpi_status status = set_u32(tmp, cap); \
- if (ACPI_FAILURE(status)) \
- return -EINVAL; \
- return count; \
-} \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
- show_bool_##value, set_bool_##value);
-
-show_set_bool(wireless, ACER_CAP_WIRELESS);
-show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
-show_set_bool(threeg, ACER_CAP_THREEG);
+static void acer_rfkill_update(struct work_struct *ignored);
+static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
+static void acer_rfkill_update(struct work_struct *ignored)
+{
+ u32 state;
+ acpi_status status;
+
+ status = get_u32(&state, ACER_CAP_WIRELESS);
+ if (ACPI_SUCCESS(status))
+ rfkill_force_state(wireless_rfkill, state ?
+ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
+
+ if (has_cap(ACER_CAP_BLUETOOTH)) {
+ status = get_u32(&state, ACER_CAP_BLUETOOTH);
+ if (ACPI_SUCCESS(status))
+ rfkill_force_state(bluetooth_rfkill, state ?
+ RFKILL_STATE_UNBLOCKED :
+ RFKILL_STATE_SOFT_BLOCKED);
+ }
+
+ schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
+}
+
+static int acer_rfkill_set(void *data, enum rfkill_state state)
+{
+ acpi_status status;
+ u32 *cap = data;
+ status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ return 0;
+}
+
+static struct rfkill * acer_rfkill_register(struct device *dev,
+enum rfkill_type type, char *name, u32 cap)
+{
+ int err;
+ u32 state;
+ u32 *data;
+ struct rfkill *rfkill_dev;
+
+ rfkill_dev = rfkill_allocate(dev, type);
+ if (!rfkill_dev)
+ return ERR_PTR(-ENOMEM);
+ rfkill_dev->name = name;
+ get_u32(&state, cap);
+ rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
+ RFKILL_STATE_SOFT_BLOCKED;
+ data = kzalloc(sizeof(u32), GFP_KERNEL);
+ if (!data) {
+ rfkill_free(rfkill_dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ *data = cap;
+ rfkill_dev->data = data;
+ rfkill_dev->toggle_radio = acer_rfkill_set;
+ rfkill_dev->user_claim_unsupported = 1;
+
+ err = rfkill_register(rfkill_dev);
+ if (err) {
+ kfree(rfkill_dev->data);
+ rfkill_free(rfkill_dev);
+ return ERR_PTR(err);
+ }
+ return rfkill_dev;
+}
+
+static int acer_rfkill_init(struct device *dev)
+{
+ wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
+ "acer-wireless", ACER_CAP_WIRELESS);
+ if (IS_ERR(wireless_rfkill))
+ return PTR_ERR(wireless_rfkill);
+
+ if (has_cap(ACER_CAP_BLUETOOTH)) {
+ bluetooth_rfkill = acer_rfkill_register(dev,
+ RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
+ ACER_CAP_BLUETOOTH);
+ if (IS_ERR(bluetooth_rfkill)) {
+ kfree(wireless_rfkill->data);
+ rfkill_unregister(wireless_rfkill);
+ return PTR_ERR(bluetooth_rfkill);
+ }
+ }
+
+ schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
+
+ return 0;
+}
+
+static void acer_rfkill_exit(void)
+{
+ cancel_delayed_work_sync(&acer_rfkill_work);
+ kfree(wireless_rfkill->data);
+ rfkill_unregister(wireless_rfkill);
+ if (has_cap(ACER_CAP_BLUETOOTH)) {
+ kfree(wireless_rfkill->data);
+ rfkill_unregister(bluetooth_rfkill);
+ }
+ return;
+}
/*
- * Read interface sysfs macro
+ * sysfs interface
*/
+static ssize_t show_bool_threeg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 result; \
+ acpi_status status = get_u32(&result, ACER_CAP_THREEG);
+ if (ACPI_SUCCESS(status))
+ return sprintf(buf, "%u\n", result);
+ return sprintf(buf, "Read error\n");
+}
+
+static ssize_t set_bool_threeg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ u32 tmp = simple_strtoul(buf, NULL, 10);
+ acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
+ if (ACPI_FAILURE(status))
+ return -EINVAL;
+ return count;
+}
+static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg,
+ set_bool_threeg);
+
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1026,7 +1116,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
goto error_brightness;
}
- return 0;
+ err = acer_rfkill_init(&device->dev);
+
+ return err;
error_brightness:
acer_led_exit();
@@ -1040,6 +1132,8 @@ static int acer_platform_remove(struct platform_device *device)
acer_led_exit();
if (has_cap(ACER_CAP_BRIGHTNESS))
acer_backlight_exit();
+
+ acer_rfkill_exit();
return 0;
}
@@ -1052,16 +1146,6 @@ pm_message_t state)
if (!data)
return -ENOMEM;
- if (has_cap(ACER_CAP_WIRELESS)) {
- get_u32(&value, ACER_CAP_WIRELESS);
- data->wireless = value;
- }
-
- if (has_cap(ACER_CAP_BLUETOOTH)) {
- get_u32(&value, ACER_CAP_BLUETOOTH);
- data->bluetooth = value;
- }
-
if (has_cap(ACER_CAP_MAILLED)) {
get_u32(&value, ACER_CAP_MAILLED);
data->mailled = value;
@@ -1082,15 +1166,6 @@ static int acer_platform_resume(struct platform_device *device)
if (!data)
return -ENOMEM;
- if (has_cap(ACER_CAP_WIRELESS))
- set_u32(data->wireless, ACER_CAP_WIRELESS);
-
- if (has_cap(ACER_CAP_BLUETOOTH))
- set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
-
- if (has_cap(ACER_CAP_THREEG))
- set_u32(data->threeg, ACER_CAP_THREEG);
-
if (has_cap(ACER_CAP_MAILLED))
set_u32(data->mailled, ACER_CAP_MAILLED);
@@ -1115,12 +1190,6 @@ static struct platform_device *acer_platform_device;
static int remove_sysfs(struct platform_device *device)
{
- if (has_cap(ACER_CAP_WIRELESS))
- device_remove_file(&device->dev, &dev_attr_wireless);
-
- if (has_cap(ACER_CAP_BLUETOOTH))
- device_remove_file(&device->dev, &dev_attr_bluetooth);
-
if (has_cap(ACER_CAP_THREEG))
device_remove_file(&device->dev, &dev_attr_threeg);
@@ -1133,20 +1202,6 @@ static int create_sysfs(void)
{
int retval = -ENOMEM;
- if (has_cap(ACER_CAP_WIRELESS)) {
- retval = device_create_file(&acer_platform_device->dev,
- &dev_attr_wireless);
- if (retval)
- goto error_sysfs;
- }
-
- if (has_cap(ACER_CAP_BLUETOOTH)) {
- retval = device_create_file(&acer_platform_device->dev,
- &dev_attr_bluetooth);
- if (retval)
- goto error_sysfs;
- }
-
if (has_cap(ACER_CAP_THREEG)) {
retval = device_create_file(&acer_platform_device->dev,
&dev_attr_threeg);
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 7c6dfd03de9..a9d5228724a 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -139,6 +139,7 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
"\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
"\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
"\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
+ "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
"\\_SB.PCI0.PX40.Q10", /* S1x */
"\\Q10"); /* A2x, L2D, L3D, M2E */
@@ -280,7 +281,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
static int read_wireless_status(int mask)
{
- ulong status;
+ unsigned long long status;
acpi_status rv = AE_OK;
if (!wireless_status_handle)
@@ -297,7 +298,7 @@ static int read_wireless_status(int mask)
static int read_gps_status(void)
{
- ulong status;
+ unsigned long long status;
acpi_status rv = AE_OK;
rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);
@@ -350,7 +351,7 @@ static void write_status(acpi_handle handle, int out, int mask)
static void object##_led_set(struct led_classdev *led_cdev, \
enum led_brightness value) \
{ \
- object##_led_wk = value; \
+ object##_led_wk = (value > 0) ? 1 : 0; \
queue_work(led_workqueue, &object##_led_work); \
} \
static void object##_led_update(struct work_struct *ignored) \
@@ -404,7 +405,7 @@ static void lcd_blank(int blank)
static int read_brightness(struct backlight_device *bd)
{
- ulong value;
+ unsigned long long value;
acpi_status rv = AE_OK;
rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
@@ -455,7 +456,7 @@ static ssize_t show_infos(struct device *dev,
struct device_attribute *attr, char *page)
{
int len = 0;
- ulong temp;
+ unsigned long long temp;
char buf[16]; //enough for all info
acpi_status rv = AE_OK;
@@ -603,7 +604,7 @@ static void set_display(int value)
static int read_display(void)
{
- ulong value = 0;
+ unsigned long long value = 0;
acpi_status rv = AE_OK;
/* In most of the case, we know how to set the display, but sometime
@@ -849,7 +850,7 @@ static int asus_hotk_get_info(void)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
- ulong bsts_result, hwrs_result;
+ unsigned long long bsts_result, hwrs_result;
char *string = NULL;
acpi_status status;
@@ -996,7 +997,7 @@ static int asus_hotk_add(struct acpi_device *device)
hotk->handle = device->handle;
strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
- acpi_driver_data(device) = hotk;
+ device->driver_data = hotk;
hotk->device = device;
result = asus_hotk_check();
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index 1ee8501e90f..9ef98b2d503 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -28,6 +28,8 @@
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <linux/uaccess.h>
+#include <linux/input.h>
+#include <linux/rfkill.h>
#define EEEPC_LAPTOP_VERSION "0.1"
@@ -125,6 +127,10 @@ struct eeepc_hotk {
by this BIOS */
uint init_flag; /* Init flags */
u16 event_count[128]; /* count for each event */
+ struct input_dev *inputdev;
+ u16 *keycode_map;
+ struct rfkill *eeepc_wlan_rfkill;
+ struct rfkill *eeepc_bluetooth_rfkill;
};
/* The actual device the driver binds to */
@@ -140,6 +146,27 @@ static struct platform_driver platform_driver = {
static struct platform_device *platform_device;
+struct key_entry {
+ char type;
+ u8 code;
+ u16 keycode;
+};
+
+enum { KE_KEY, KE_END };
+
+static struct key_entry eeepc_keymap[] = {
+ /* Sleep already handled via generic ACPI code */
+ {KE_KEY, 0x10, KEY_WLAN },
+ {KE_KEY, 0x12, KEY_PROG1 },
+ {KE_KEY, 0x13, KEY_MUTE },
+ {KE_KEY, 0x14, KEY_VOLUMEDOWN },
+ {KE_KEY, 0x15, KEY_VOLUMEUP },
+ {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
+ {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
+ {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
+ {KE_END, 0},
+};
+
/*
* The hotkey driver declaration
*/
@@ -204,7 +231,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
static int read_acpi_int(acpi_handle handle, const char *method, int *val)
{
acpi_status status;
- ulong result;
+ unsigned long long result;
status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
if (ACPI_FAILURE(status)) {
@@ -261,6 +288,44 @@ static int update_bl_status(struct backlight_device *bd)
}
/*
+ * Rfkill helpers
+ */
+
+static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
+{
+ if (state == RFKILL_STATE_SOFT_BLOCKED)
+ return set_acpi(CM_ASL_WLAN, 0);
+ else
+ return set_acpi(CM_ASL_WLAN, 1);
+}
+
+static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
+{
+ if (get_acpi(CM_ASL_WLAN) == 1)
+ *state = RFKILL_STATE_UNBLOCKED;
+ else
+ *state = RFKILL_STATE_SOFT_BLOCKED;
+ return 0;
+}
+
+static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
+{
+ if (state == RFKILL_STATE_SOFT_BLOCKED)
+ return set_acpi(CM_ASL_BLUETOOTH, 0);
+ else
+ return set_acpi(CM_ASL_BLUETOOTH, 1);
+}
+
+static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
+{
+ if (get_acpi(CM_ASL_BLUETOOTH) == 1)
+ *state = RFKILL_STATE_UNBLOCKED;
+ else
+ *state = RFKILL_STATE_SOFT_BLOCKED;
+ return 0;
+}
+
+/*
* Sys helpers
*/
static int parse_arg(const char *buf, unsigned long count, int *val)
@@ -311,13 +376,11 @@ static ssize_t show_sys_acpi(int cm, char *buf)
EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
-EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN);
static struct attribute *platform_attributes[] = {
&dev_attr_camera.attr,
&dev_attr_cardr.attr,
&dev_attr_disp.attr,
- &dev_attr_wlan.attr,
NULL
};
@@ -328,8 +391,64 @@ static struct attribute_group platform_attribute_group = {
/*
* Hotkey functions
*/
+static struct key_entry *eepc_get_entry_by_scancode(int code)
+{
+ struct key_entry *key;
+
+ for (key = eeepc_keymap; key->type != KE_END; key++)
+ if (code == key->code)
+ return key;
+
+ return NULL;
+}
+
+static struct key_entry *eepc_get_entry_by_keycode(int code)
+{
+ struct key_entry *key;
+
+ for (key = eeepc_keymap; key->type != KE_END; key++)
+ if (code == key->keycode && key->type == KE_KEY)
+ return key;
+
+ return NULL;
+}
+
+static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+{
+ struct key_entry *key = eepc_get_entry_by_scancode(scancode);
+
+ if (key && key->type == KE_KEY) {
+ *keycode = key->keycode;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
+{
+ struct key_entry *key;
+ int old_keycode;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ key = eepc_get_entry_by_scancode(scancode);
+ if (key && key->type == KE_KEY) {
+ old_keycode = key->keycode;
+ key->keycode = keycode;
+ set_bit(keycode, dev->keybit);
+ if (!eepc_get_entry_by_keycode(old_keycode))
+ clear_bit(old_keycode, dev->keybit);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static int eeepc_hotk_check(void)
{
+ const struct key_entry *key;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
int result;
@@ -356,6 +475,31 @@ static int eeepc_hotk_check(void)
"Get control methods supported: 0x%x\n",
ehotk->cm_supported);
}
+ ehotk->inputdev = input_allocate_device();
+ if (!ehotk->inputdev) {
+ printk(EEEPC_INFO "Unable to allocate input device\n");
+ return 0;
+ }
+ ehotk->inputdev->name = "Asus EeePC extra buttons";
+ ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
+ ehotk->inputdev->id.bustype = BUS_HOST;
+ ehotk->inputdev->getkeycode = eeepc_getkeycode;
+ ehotk->inputdev->setkeycode = eeepc_setkeycode;
+
+ for (key = eeepc_keymap; key->type != KE_END; key++) {
+ switch (key->type) {
+ case KE_KEY:
+ set_bit(EV_KEY, ehotk->inputdev->evbit);
+ set_bit(key->keycode, ehotk->inputdev->keybit);
+ break;
+ }
+ }
+ result = input_register_device(ehotk->inputdev);
+ if (result) {
+ printk(EEEPC_INFO "Unable to register input device\n");
+ input_free_device(ehotk->inputdev);
+ return 0;
+ }
} else {
printk(EEEPC_ERR "Hotkey device not present, aborting\n");
return -EINVAL;
@@ -363,21 +507,6 @@ static int eeepc_hotk_check(void)
return 0;
}
-static void notify_wlan(u32 *event)
-{
- /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2
- will always be 0x10 */
- if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) {
- const char *method = cm_getv[CM_ASL_WLAN];
- int value;
- if (read_acpi_int(ehotk->handle, method, &value))
- printk(EEEPC_WARNING "Error reading %s\n",
- method);
- else if (value == 1)
- *event = 0x11;
- }
-}
-
static void notify_brn(void)
{
struct backlight_device *bd = eeepc_backlight_device;
@@ -386,14 +515,28 @@ static void notify_brn(void)
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
{
+ static struct key_entry *key;
if (!ehotk)
return;
- if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag))
- notify_wlan(&event);
if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
notify_brn();
acpi_bus_generate_proc_event(ehotk->device, event,
ehotk->event_count[event % 128]++);
+ if (ehotk->inputdev) {
+ key = eepc_get_entry_by_scancode(event);
+ if (key) {
+ switch (key->type) {
+ case KE_KEY:
+ input_report_key(ehotk->inputdev, key->keycode,
+ 1);
+ input_sync(ehotk->inputdev);
+ input_report_key(ehotk->inputdev, key->keycode,
+ 0);
+ input_sync(ehotk->inputdev);
+ break;
+ }
+ }
+ }
}
static int eeepc_hotk_add(struct acpi_device *device)
@@ -411,7 +554,7 @@ static int eeepc_hotk_add(struct acpi_device *device)
ehotk->handle = device->handle;
strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
- acpi_driver_data(device) = ehotk;
+ device->driver_data = ehotk;
ehotk->device = device;
result = eeepc_hotk_check();
if (result)
@@ -420,6 +563,47 @@ static int eeepc_hotk_add(struct acpi_device *device)
eeepc_hotk_notify, ehotk);
if (ACPI_FAILURE(status))
printk(EEEPC_ERR "Error installing notify handler\n");
+
+ if (get_acpi(CM_ASL_WLAN) != -1) {
+ ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
+ RFKILL_TYPE_WLAN);
+
+ if (!ehotk->eeepc_wlan_rfkill)
+ goto end;
+
+ ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
+ ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
+ ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
+ if (get_acpi(CM_ASL_WLAN) == 1)
+ ehotk->eeepc_wlan_rfkill->state =
+ RFKILL_STATE_UNBLOCKED;
+ else
+ ehotk->eeepc_wlan_rfkill->state =
+ RFKILL_STATE_SOFT_BLOCKED;
+ rfkill_register(ehotk->eeepc_wlan_rfkill);
+ }
+
+ if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
+ ehotk->eeepc_bluetooth_rfkill =
+ rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
+
+ if (!ehotk->eeepc_bluetooth_rfkill)
+ goto end;
+
+ ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
+ ehotk->eeepc_bluetooth_rfkill->toggle_radio =
+ eeepc_bluetooth_rfkill_set;
+ ehotk->eeepc_bluetooth_rfkill->get_state =
+ eeepc_bluetooth_rfkill_state;
+ if (get_acpi(CM_ASL_BLUETOOTH) == 1)
+ ehotk->eeepc_bluetooth_rfkill->state =
+ RFKILL_STATE_UNBLOCKED;
+ else
+ ehotk->eeepc_bluetooth_rfkill->state =
+ RFKILL_STATE_SOFT_BLOCKED;
+ rfkill_register(ehotk->eeepc_bluetooth_rfkill);
+ }
+
end:
if (result) {
kfree(ehotk);
@@ -553,6 +737,12 @@ static void eeepc_backlight_exit(void)
{
if (eeepc_backlight_device)
backlight_device_unregister(eeepc_backlight_device);
+ if (ehotk->inputdev)
+ input_unregister_device(ehotk->inputdev);
+ if (ehotk->eeepc_wlan_rfkill)
+ rfkill_unregister(ehotk->eeepc_wlan_rfkill);
+ if (ehotk->eeepc_bluetooth_rfkill)
+ rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
eeepc_backlight_device = NULL;
}
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index 3e56203e494..d2cf0bfe316 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -44,8 +44,9 @@
* Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
* also supported by this driver.
*
- * This driver has been tested on a Fujitsu Lifebook S6410 and S7020. It
- * should work on most P-series and S-series Lifebooks, but YMMV.
+ * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
+ * P8010. It should work on most P-series and S-series Lifebooks, but
+ * YMMV.
*
* The module parameter use_alt_lcd_levels switches between different ACPI
* brightness controls which are used by different Fujitsu laptops. In most
@@ -65,7 +66,7 @@
#include <linux/video_output.h>
#include <linux/platform_device.h>
-#define FUJITSU_DRIVER_VERSION "0.4.2"
+#define FUJITSU_DRIVER_VERSION "0.4.3"
#define FUJITSU_LCD_N_LEVELS 8
@@ -83,10 +84,10 @@
#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
/* Hotkey details */
-#define LOCK_KEY 0x410 /* codes for the keys in the GIRB register */
-#define DISPLAY_KEY 0x411 /* keys are mapped to KEY_SCREENLOCK (the key with the key symbol) */
-#define ENERGY_KEY 0x412 /* KEY_MEDIA (the key with the laptop symbol, KEY_EMAIL (E key)) */
-#define REST_KEY 0x413 /* KEY_SUSPEND (R key) */
+#define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */
+#define KEY2_CODE 0x411
+#define KEY3_CODE 0x412
+#define KEY4_CODE 0x413
#define MAX_HOTKEY_RINGBUFFER_SIZE 100
#define RINGBUFFERSIZE 40
@@ -123,6 +124,7 @@ struct fujitsu_t {
char phys[32];
struct backlight_device *bl_device;
struct platform_device *pf_device;
+ int keycode1, keycode2, keycode3, keycode4;
unsigned int max_brightness;
unsigned int brightness_changed;
@@ -224,7 +226,7 @@ static int set_lcd_level_alt(int level)
static int get_lcd_level(void)
{
- unsigned long state = 0;
+ unsigned long long state = 0;
acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
@@ -246,7 +248,7 @@ static int get_lcd_level(void)
static int get_max_brightness(void)
{
- unsigned long state = 0;
+ unsigned long long state = 0;
acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
@@ -263,7 +265,7 @@ static int get_max_brightness(void)
static int get_lcd_level_alt(void)
{
- unsigned long state = 0;
+ unsigned long long state = 0;
acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n");
@@ -384,7 +386,7 @@ static ssize_t store_lcd_level(struct device *dev,
static int get_irb(void)
{
- unsigned long state = 0;
+ unsigned long long state = 0;
acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n");
@@ -430,7 +432,7 @@ static struct platform_driver fujitsupf_driver = {
}
};
-static int dmi_check_cb_s6410(const struct dmi_system_id *id)
+static void dmi_check_cb_common(const struct dmi_system_id *id)
{
acpi_handle handle;
int have_blnf;
@@ -452,24 +454,40 @@ static int dmi_check_cb_s6410(const struct dmi_system_id *id)
"auto-detecting disable_adjust\n");
disable_brightness_adjust = have_blnf ? 0 : 1;
}
+}
+
+static int dmi_check_cb_s6410(const struct dmi_system_id *id)
+{
+ dmi_check_cb_common(id);
+ fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */
+ fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */
+ return 0;
+}
+
+static int dmi_check_cb_p8010(const struct dmi_system_id *id)
+{
+ dmi_check_cb_common(id);
+ fujitsu->keycode1 = KEY_HELP; /* "Support" */
+ fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */
+ fujitsu->keycode4 = KEY_WWW; /* "Internet" */
return 0;
}
static struct dmi_system_id __initdata fujitsu_dmi_table[] = {
{
- .ident = "Fujitsu Siemens",
+ .ident = "Fujitsu Siemens S6410",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
},
.callback = dmi_check_cb_s6410},
{
- .ident = "FUJITSU LifeBook P8010",
+ .ident = "Fujitsu LifeBook P8010",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
- },
- .callback = dmi_check_cb_s6410},
+ },
+ .callback = dmi_check_cb_p8010},
{}
};
@@ -490,7 +508,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
fujitsu->acpi_handle = device->handle;
sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
- acpi_driver_data(device) = fujitsu;
+ device->driver_data = fujitsu;
status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
@@ -547,7 +565,6 @@ static int acpi_fujitsu_add(struct acpi_device *device)
}
/* do config (detect defaults) */
- dmi_check_system(fujitsu_dmi_table);
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;
@@ -623,17 +640,17 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
keycode = 0;
if (disable_brightness_keys != 1) {
if (oldb == 0) {
- acpi_bus_generate_proc_event(fujitsu->
- dev,
- ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
- 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);
+ acpi_bus_generate_proc_event
+ (fujitsu->dev,
+ ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
+ 0);
keycode = KEY_BRIGHTNESSUP;
}
}
@@ -646,8 +663,7 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
}
if (disable_brightness_keys != 1) {
acpi_bus_generate_proc_event(fujitsu->dev,
- ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
- 0);
+ ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0);
keycode = KEY_BRIGHTNESSUP;
}
} else if (oldb > newb) {
@@ -659,8 +675,7 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
}
if (disable_brightness_keys != 1) {
acpi_bus_generate_proc_event(fujitsu->dev,
- ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
- 0);
+ ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0);
keycode = KEY_BRIGHTNESSDOWN;
}
} else {
@@ -703,7 +718,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
sprintf(acpi_device_name(device), "%s",
ACPI_FUJITSU_HOTKEY_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
- acpi_driver_data(device) = fujitsu_hotkey;
+ device->driver_data = fujitsu_hotkey;
status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
@@ -742,10 +757,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
input->id.product = 0x06;
input->dev.parent = &device->dev;
input->evbit[0] = BIT(EV_KEY);
- set_bit(KEY_SCREENLOCK, input->keybit);
- set_bit(KEY_MEDIA, input->keybit);
- set_bit(KEY_EMAIL, input->keybit);
- set_bit(KEY_SUSPEND, input->keybit);
+ set_bit(fujitsu->keycode1, input->keybit);
+ set_bit(fujitsu->keycode2, input->keybit);
+ set_bit(fujitsu->keycode3, input->keybit);
+ set_bit(fujitsu->keycode4, input->keybit);
set_bit(KEY_UNKNOWN, input->keybit);
error = input_register_device(input);
@@ -833,24 +848,24 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
irb);
switch (irb & 0x4ff) {
- case LOCK_KEY:
- keycode = KEY_SCREENLOCK;
+ case KEY1_CODE:
+ keycode = fujitsu->keycode1;
break;
- case DISPLAY_KEY:
- keycode = KEY_MEDIA;
+ case KEY2_CODE:
+ keycode = fujitsu->keycode2;
break;
- case ENERGY_KEY:
- keycode = KEY_EMAIL;
+ case KEY3_CODE:
+ keycode = fujitsu->keycode3;
break;
- case REST_KEY:
- keycode = KEY_SUSPEND;
+ case KEY4_CODE:
+ keycode = fujitsu->keycode4;
break;
case 0:
keycode = 0;
break;
default:
vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Unknown GIRB result [%x]\n", irb);
+ "Unknown GIRB result [%x]\n", irb);
keycode = -1;
break;
}
@@ -859,12 +874,12 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
"Push keycode into ringbuffer [%d]\n",
keycode);
status = kfifo_put(fujitsu_hotkey->fifo,
- (unsigned char *)&keycode,
- sizeof(keycode));
+ (unsigned char *)&keycode,
+ sizeof(keycode));
if (status != sizeof(keycode)) {
vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Could not push keycode [0x%x]\n",
- keycode);
+ "Could not push keycode [0x%x]\n",
+ keycode);
} else {
input_report_key(input, keycode, 1);
input_sync(input);
@@ -879,8 +894,8 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
input_report_key(input, keycode_r, 0);
input_sync(input);
vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "Pop keycode from ringbuffer [%d]\n",
- keycode_r);
+ "Pop keycode from ringbuffer [%d]\n",
+ keycode_r);
}
}
}
@@ -943,6 +958,11 @@ static int __init fujitsu_init(void)
if (!fujitsu)
return -ENOMEM;
memset(fujitsu, 0, sizeof(struct fujitsu_t));
+ fujitsu->keycode1 = KEY_PROG1;
+ fujitsu->keycode2 = KEY_PROG2;
+ fujitsu->keycode3 = KEY_PROG3;
+ fujitsu->keycode4 = KEY_PROG4;
+ dmi_check_system(fujitsu_dmi_table);
result = acpi_bus_register_driver(&acpi_fujitsu_driver);
if (result < 0) {
@@ -1076,15 +1096,14 @@ 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:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
+MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
+MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
static struct pnp_device_id pnp_ids[] = {
- { .id = "FUJ02bf" },
- { .id = "FUJ02B1" },
- { .id = "FUJ02E3" },
- { .id = "" }
+ {.id = "FUJ02bf"},
+ {.id = "FUJ02B1"},
+ {.id = "FUJ02E3"},
+ {.id = ""}
};
+
MODULE_DEVICE_TABLE(pnp, pnp_ids);
diff --git a/drivers/misc/hp-wmi.c b/drivers/misc/hp-wmi.c
index 5dabfb69ee5..4b7c24c519c 100644
--- a/drivers/misc/hp-wmi.c
+++ b/drivers/misc/hp-wmi.c
@@ -82,6 +82,7 @@ static struct key_entry hp_wmi_keymap[] = {
{KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
{KE_KEY, 0x20e6, KEY_PROG1},
{KE_KEY, 0x2142, KEY_MEDIA},
+ {KE_KEY, 0x213b, KEY_INFO},
{KE_KEY, 0x231b, KEY_HELP},
{KE_END, 0}
};
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
index 80a13635240..e00a2756e97 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/misc/intel_menlow.c
@@ -57,7 +57,7 @@ static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
- unsigned long value;
+ unsigned long long value;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
@@ -90,7 +90,7 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
- unsigned long value;
+ unsigned long long value;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
@@ -104,7 +104,7 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
if (ACPI_FAILURE(status))
return -EFAULT;
- return sprintf(buf, "%ld\n", value);
+ return sprintf(buf, "%llu\n", value);
}
static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
@@ -115,7 +115,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status;
- int temp;
+ unsigned long long temp;
unsigned long max_state;
if (memory_get_int_max_bandwidth(cdev, &max_state))
@@ -131,7 +131,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
status =
acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
- (unsigned long *)&temp);
+ &temp);
printk(KERN_INFO
"Bandwidth value was %d: status is %d\n", state, status);
@@ -175,7 +175,7 @@ static int intel_menlow_memory_add(struct acpi_device *device)
goto end;
}
- acpi_driver_data(device) = cdev;
+ device->driver_data = cdev;
result = sysfs_create_link(&device->dev.kobj,
&cdev->device.kobj, "thermal_cooling");
if (result)
@@ -252,7 +252,8 @@ static DEFINE_MUTEX(intel_menlow_attr_lock);
* @auxtype : AUX0/AUX1
* @buf: syfs buffer
*/
-static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
+static int sensor_get_auxtrip(acpi_handle handle, int index,
+ unsigned long long *value)
{
acpi_status status;
@@ -260,7 +261,7 @@ static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
return -EINVAL;
status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
- NULL, (unsigned long *)value);
+ NULL, value);
if (ACPI_FAILURE(status))
return -EIO;
@@ -282,13 +283,13 @@ static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
struct acpi_object_list args = {
1, &arg
};
- int temp;
+ unsigned long long temp;
if (index != 0 && index != 1)
return -EINVAL;
status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
- NULL, (unsigned long *)&temp);
+ NULL, &temp);
if (ACPI_FAILURE(status))
return -EIO;
if ((index && value < temp) || (!index && value > temp))
@@ -296,7 +297,7 @@ static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
arg.integer.value = value;
status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
- &args, (unsigned long *)&temp);
+ &args, &temp);
if (ACPI_FAILURE(status))
return -EIO;
@@ -312,7 +313,7 @@ static ssize_t aux0_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
- int value;
+ unsigned long long value;
int result;
result = sensor_get_auxtrip(attr->handle, 0, &value);
@@ -324,7 +325,7 @@ static ssize_t aux1_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
- int value;
+ unsigned long long value;
int result;
result = sensor_get_auxtrip(attr->handle, 1, &value);
@@ -376,7 +377,7 @@ static ssize_t bios_enabled_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
acpi_status status;
- unsigned long bios_enabled;
+ unsigned long long bios_enabled;
status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
if (ACPI_FAILURE(status))
@@ -492,7 +493,7 @@ static int __init intel_menlow_module_init(void)
{
int result = -ENODEV;
acpi_status status;
- unsigned long enable;
+ unsigned long long enable;
if (acpi_disabled)
return result;
diff --git a/drivers/misc/panasonic-laptop.c b/drivers/misc/panasonic-laptop.c
new file mode 100644
index 00000000000..a2cb598d8ab
--- /dev/null
+++ b/drivers/misc/panasonic-laptop.c
@@ -0,0 +1,767 @@
+/*
+ * Panasonic HotKey and LCD brightness control driver
+ * (C) 2004 Hiroshi Miura <miura@da-cha.org>
+ * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
+ * (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp>
+ * (C) 2004 David Bronaugh <dbronaugh>
+ * (C) 2006-2008 Harald Welte <laforge@gnumonks.org>
+ *
+ * derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte
+ *
+ * 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
+ * publicshed 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *---------------------------------------------------------------------------
+ *
+ * ChangeLog:
+ * Sep.23, 2008 Harald Welte <laforge@gnumonks.org>
+ * -v0.95 rename driver from drivers/acpi/pcc_acpi.c to
+ * drivers/misc/panasonic-laptop.c
+ *
+ * Jul.04, 2008 Harald Welte <laforge@gnumonks.org>
+ * -v0.94 replace /proc interface with device attributes
+ * support {set,get}keycode on th input device
+ *
+ * Jun.27, 2008 Harald Welte <laforge@gnumonks.org>
+ * -v0.92 merge with 2.6.26-rc6 input API changes
+ * remove broken <= 2.6.15 kernel support
+ * resolve all compiler warnings
+ * various coding style fixes (checkpatch.pl)
+ * add support for backlight api
+ * major code restructuring
+ *
+ * Dac.28, 2007 Harald Welte <laforge@gnumonks.org>
+ * -v0.91 merge with 2.6.24-rc6 ACPI changes
+ *
+ * Nov.04, 2006 Hiroshi Miura <miura@da-cha.org>
+ * -v0.9 remove warning about section reference.
+ * remove acpi_os_free
+ * add /proc/acpi/pcc/brightness interface for HAL access
+ * merge dbronaugh's enhancement
+ * Aug.17, 2004 David Bronaugh (dbronaugh)
+ * - Added screen brightness setting interface
+ * Thanks to FreeBSD crew (acpi_panasonic.c)
+ * for the ideas I needed to accomplish it
+ *
+ * May.29, 2006 Hiroshi Miura <miura@da-cha.org>
+ * -v0.8.4 follow to change keyinput structure
+ * thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>,
+ * Jacob Bower <jacob.bower@ic.ac.uk> and
+ * Hiroshi Yokota for providing solutions.
+ *
+ * Oct.02, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.8.2 merge code of YOKOTA Hiroshi
+ * <yokota@netlab.is.tsukuba.ac.jp>.
+ * Add sticky key mode interface.
+ * Refactoring acpi_pcc_generate_keyinput().
+ *
+ * Sep.15, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.8 Generate key input event on input subsystem.
+ * This is based on yet another driver written by
+ * Ryuta Nakanishi.
+ *
+ * Sep.10, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.7 Change proc interface functions using seq_file
+ * facility as same as other ACPI drivers.
+ *
+ * Aug.28, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.6.4 Fix a silly error with status checking
+ *
+ * Aug.25, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.6.3 replace read_acpi_int by standard function
+ * acpi_evaluate_integer
+ * some clean up and make smart copyright notice.
+ * fix return value of pcc_acpi_get_key()
+ * fix checking return value of acpi_bus_register_driver()
+ *
+ * Aug.22, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * -v0.6.2 Add check on ACPI data (num_sifr)
+ * Coding style cleanups, better error messages/handling
+ * Fixed an off-by-one error in memory allocation
+ *
+ * Aug.21, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * -v0.6.1 Fix a silly error with status checking
+ *
+ * Aug.20, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * - v0.6 Correct brightness controls to reflect reality
+ * based on information gleaned by Hiroshi Miura
+ * and discussions with Hiroshi Miura
+ *
+ * Aug.10, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.5 support LCD brightness control
+ * based on the disclosed information by MEI.
+ *
+ * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.4 first post version
+ * add function to retrive SIFR
+ *
+ * Jul.24, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.3 get proper status of hotkey
+ *
+ * Jul.22, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.2 add HotKey handler
+ *
+ * Jul.17, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.1 start from toshiba_acpi driver written by John Belmonte
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/backlight.h>
+#include <linux/ctype.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/input.h>
+
+
+#ifndef ACPI_HOTKEY_COMPONENT
+#define ACPI_HOTKEY_COMPONENT 0x10000000
+#endif
+
+#define _COMPONENT ACPI_HOTKEY_COMPONENT
+
+MODULE_AUTHOR("Hiroshi Miura, David Bronaugh and Harald Welte");
+MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops");
+MODULE_LICENSE("GPL");
+
+#define LOGPREFIX "pcc_acpi: "
+
+/* Define ACPI PATHs */
+/* Lets note hotkeys */
+#define METHOD_HKEY_QUERY "HINF"
+#define METHOD_HKEY_SQTY "SQTY"
+#define METHOD_HKEY_SINF "SINF"
+#define METHOD_HKEY_SSET "SSET"
+#define HKEY_NOTIFY 0x80
+
+#define ACPI_PCC_DRIVER_NAME "Panasonic Laptop Support"
+#define ACPI_PCC_DEVICE_NAME "Hotkey"
+#define ACPI_PCC_CLASS "pcc"
+
+#define ACPI_PCC_INPUT_PHYS "panasonic/hkey0"
+
+/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
+ ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00
+*/
+enum SINF_BITS { SINF_NUM_BATTERIES = 0,
+ SINF_LCD_TYPE,
+ SINF_AC_MAX_BRIGHT,
+ SINF_AC_MIN_BRIGHT,
+ SINF_AC_CUR_BRIGHT,
+ SINF_DC_MAX_BRIGHT,
+ SINF_DC_MIN_BRIGHT,
+ SINF_DC_CUR_BRIGHT,
+ SINF_MUTE,
+ SINF_RESERVED,
+ SINF_ENV_STATE,
+ SINF_STICKY_KEY = 0x80,
+ };
+/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
+
+static int acpi_pcc_hotkey_add(struct acpi_device *device);
+static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type);
+static int acpi_pcc_hotkey_resume(struct acpi_device *device);
+
+static const struct acpi_device_id pcc_device_ids[] = {
+ { "MAT0012", 0},
+ { "MAT0013", 0},
+ { "MAT0018", 0},
+ { "MAT0019", 0},
+ { "", 0},
+};
+
+static struct acpi_driver acpi_pcc_driver = {
+ .name = ACPI_PCC_DRIVER_NAME,
+ .class = ACPI_PCC_CLASS,
+ .ids = pcc_device_ids,
+ .ops = {
+ .add = acpi_pcc_hotkey_add,
+ .remove = acpi_pcc_hotkey_remove,
+ .resume = acpi_pcc_hotkey_resume,
+ },
+};
+
+#define KEYMAP_SIZE 11
+static const int initial_keymap[KEYMAP_SIZE] = {
+ /* 0 */ KEY_RESERVED,
+ /* 1 */ KEY_BRIGHTNESSDOWN,
+ /* 2 */ KEY_BRIGHTNESSUP,
+ /* 3 */ KEY_DISPLAYTOGGLE,
+ /* 4 */ KEY_MUTE,
+ /* 5 */ KEY_VOLUMEDOWN,
+ /* 6 */ KEY_VOLUMEUP,
+ /* 7 */ KEY_SLEEP,
+ /* 8 */ KEY_PROG1, /* Change CPU boost */
+ /* 9 */ KEY_BATTERY,
+ /* 10 */ KEY_SUSPEND,
+};
+
+struct pcc_acpi {
+ acpi_handle handle;
+ unsigned long num_sifr;
+ int sticky_mode;
+ u32 *sinf;
+ struct acpi_device *device;
+ struct input_dev *input_dev;
+ struct backlight_device *backlight;
+ int keymap[KEYMAP_SIZE];
+};
+
+struct pcc_keyinput {
+ struct acpi_hotkey *hotkey;
+};
+
+/* method access functions */
+static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
+{
+ union acpi_object in_objs[] = {
+ { .integer.type = ACPI_TYPE_INTEGER,
+ .integer.value = func, },
+ { .integer.type = ACPI_TYPE_INTEGER,
+ .integer.value = val, },
+ };
+ struct acpi_object_list params = {
+ .count = ARRAY_SIZE(in_objs),
+ .pointer = in_objs,
+ };
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_write_sset");
+
+ status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
+ &params, NULL);
+
+ return status == AE_OK;
+}
+
+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))
+ return s;
+ else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "evaluation error HKEY.SQTY\n"));
+ return -EINVAL;
+ }
+}
+
+static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ 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)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "evaluation error HKEY.SINF\n"));
+ return 0;
+ }
+
+ hkey = buffer.pointer;
+ if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
+ goto end;
+ }
+
+ if (pcc->num_sifr < hkey->package.count) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "SQTY reports bad SINF length\n"));
+ status = AE_ERROR;
+ goto end;
+ }
+
+ for (i = 0; i < hkey->package.count; i++) {
+ union acpi_object *element = &(hkey->package.elements[i]);
+ if (likely(element->type == ACPI_TYPE_INTEGER)) {
+ sinf[i] = element->integer.value;
+ } else
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Invalid HKEY.SINF data\n"));
+ }
+ sinf[hkey->package.count] = -1;
+
+end:
+ kfree(buffer.pointer);
+ return status == AE_OK;
+}
+
+/* backlight API interface functions */
+
+/* This driver currently treats AC and DC brightness identical,
+ * since we don't need to invent an interface to the core ACPI
+ * logic to receive events in case a power supply is plugged in
+ * or removed */
+
+static int bl_get(struct backlight_device *bd)
+{
+ struct pcc_acpi *pcc = bl_get_data(bd);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return pcc->sinf[SINF_AC_CUR_BRIGHT];
+}
+
+static int bl_set_status(struct backlight_device *bd)
+{
+ struct pcc_acpi *pcc = bl_get_data(bd);
+ int bright = bd->props.brightness;
+ int rc;
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
+ bright = pcc->sinf[SINF_AC_MIN_BRIGHT];
+
+ if (bright < pcc->sinf[SINF_DC_MIN_BRIGHT])
+ bright = pcc->sinf[SINF_DC_MIN_BRIGHT];
+
+ if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT] ||
+ bright > pcc->sinf[SINF_AC_MAX_BRIGHT])
+ return -EINVAL;
+
+ rc = acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, bright);
+ if (rc < 0)
+ return rc;
+
+ return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright);
+}
+
+static struct backlight_ops pcc_backlight_ops = {
+ .get_brightness = bl_get,
+ .update_status = bl_set_status,
+};
+
+
+/* sysfs user interface functions */
+
+static ssize_t show_numbatt(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return sprintf(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
+}
+
+static ssize_t show_lcdtype(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return sprintf(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
+}
+
+static ssize_t show_mute(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return sprintf(buf, "%u\n", pcc->sinf[SINF_MUTE]);
+}
+
+static ssize_t show_sticky(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return sprintf(buf, "%u\n", pcc->sinf[SINF_STICKY_KEY]);
+}
+
+static ssize_t set_sticky(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+ int val;
+
+ if (count && sscanf(buf, "%i", &val) == 1 &&
+ (val == 0 || val == 1)) {
+ acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, val);
+ pcc->sticky_mode = val;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(numbatt, S_IRUGO, show_numbatt, NULL);
+static DEVICE_ATTR(lcdtype, S_IRUGO, show_lcdtype, NULL);
+static DEVICE_ATTR(mute, S_IRUGO, show_mute, NULL);
+static DEVICE_ATTR(sticky_key, S_IRUGO | S_IWUSR, show_sticky, set_sticky);
+
+static struct attribute *pcc_sysfs_entries[] = {
+ &dev_attr_numbatt.attr,
+ &dev_attr_lcdtype.attr,
+ &dev_attr_mute.attr,
+ &dev_attr_sticky_key.attr,
+ NULL,
+};
+
+static struct attribute_group pcc_attr_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = pcc_sysfs_entries,
+};
+
+
+/* hotkey input device driver */
+
+static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+{
+ struct pcc_acpi *pcc = input_get_drvdata(dev);
+
+ if (scancode >= ARRAY_SIZE(pcc->keymap))
+ return -EINVAL;
+
+ *keycode = pcc->keymap[scancode];
+
+ return 0;
+}
+
+static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) {
+ if (pcc->keymap[i] == keycode)
+ return i+1;
+ }
+
+ return 0;
+}
+
+static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
+{
+ struct pcc_acpi *pcc = input_get_drvdata(dev);
+ int oldkeycode;
+
+ if (scancode >= ARRAY_SIZE(pcc->keymap))
+ return -EINVAL;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ oldkeycode = pcc->keymap[scancode];
+ pcc->keymap[scancode] = keycode;
+
+ set_bit(keycode, dev->keybit);
+
+ if (!keymap_get_by_keycode(pcc, oldkeycode))
+ clear_bit(oldkeycode, dev->keybit);
+
+ return 0;
+}
+
+static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
+{
+ struct input_dev *hotk_input_dev = pcc->input_dev;
+ int rc;
+ 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)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "error getting hotkey status\n"));
+ return;
+ }
+
+ acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
+
+ hkey_num = result & 0xf;
+
+ if (hkey_num < 0 || hkey_num > ARRAY_SIZE(pcc->keymap)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "hotkey number out of range: %d\n",
+ hkey_num));
+ return;
+ }
+
+ key_code = pcc->keymap[hkey_num];
+
+ if (key_code != KEY_RESERVED) {
+ int pushed = (result & 0x80) ? TRUE : FALSE;
+
+ input_report_key(hotk_input_dev, key_code, pushed);
+ input_sync(hotk_input_dev);
+ }
+
+ return;
+}
+
+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);
+ break;
+ default:
+ /* nothing to do */
+ break;
+ }
+}
+
+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,
+ "Couldn't allocate input device for hotkey"));
+ return -ENOMEM;
+ }
+
+ pcc->input_dev->evbit[0] = BIT(EV_KEY);
+
+ pcc->input_dev->name = ACPI_PCC_DRIVER_NAME;
+ pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS;
+ pcc->input_dev->id.bustype = BUS_HOST;
+ pcc->input_dev->id.vendor = 0x0001;
+ pcc->input_dev->id.product = 0x0001;
+ pcc->input_dev->id.version = 0x0100;
+ pcc->input_dev->getkeycode = pcc_getkeycode;
+ pcc->input_dev->setkeycode = pcc_setkeycode;
+
+ /* load initial keymap */
+ memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap));
+
+ for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++)
+ __set_bit(pcc->keymap[i], pcc->input_dev->keybit);
+ __clear_bit(KEY_RESERVED, pcc->input_dev->keybit);
+
+ input_set_drvdata(pcc->input_dev, pcc);
+
+ rc = input_register_device(pcc->input_dev);
+ if (rc < 0)
+ input_free_device(pcc->input_dev);
+
+ return rc;
+}
+
+/* kernel module interface */
+
+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;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n",
+ pcc->sticky_mode));
+
+ status = acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
+
+ return status == AE_OK ? 0 : -EINVAL;
+}
+
+static int acpi_pcc_hotkey_add(struct acpi_device *device)
+{
+ acpi_status status;
+ struct pcc_acpi *pcc;
+ int num_sifr, result;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add");
+
+ if (!device)
+ return -EINVAL;
+
+ num_sifr = acpi_pcc_get_sqty(device);
+
+ if (num_sifr > 255) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large"));
+ return -ENODEV;
+ }
+
+ pcc = kzalloc(sizeof(struct pcc_acpi), GFP_KERNEL);
+ if (!pcc) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't allocate mem for pcc"));
+ return -ENOMEM;
+ }
+
+ pcc->sinf = kzalloc(sizeof(u32) * (num_sifr + 1), GFP_KERNEL);
+ if (!pcc->sinf) {
+ result = -ENOMEM;
+ goto out_hotkey;
+ }
+
+ pcc->device = device;
+ pcc->handle = device->handle;
+ pcc->num_sifr = num_sifr;
+ device->driver_data = pcc;
+ strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PCC_CLASS);
+
+ result = acpi_pcc_init_input(pcc);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing keyinput handler\n"));
+ goto out_sinf;
+ }
+
+ /* initialize hotkey input device */
+ status = acpi_install_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
+ acpi_pcc_hotkey_notify, pcc);
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ result = -ENODEV;
+ goto out_input;
+ }
+
+ /* initialize backlight */
+ pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
+ &pcc_backlight_ops);
+ if (IS_ERR(pcc->backlight))
+ goto out_notify;
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't retrieve BIOS data\n"));
+ goto out_backlight;
+ }
+
+ /* read the initial brightness setting from the hardware */
+ pcc->backlight->props.max_brightness =
+ pcc->sinf[SINF_AC_MAX_BRIGHT];
+ pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
+
+ /* read the initial sticky key mode from the hardware */
+ pcc->sticky_mode = pcc->sinf[SINF_STICKY_KEY];
+
+ /* add sysfs attributes */
+ result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group);
+ if (result)
+ goto out_backlight;
+
+ return 0;
+
+out_backlight:
+ backlight_device_unregister(pcc->backlight);
+out_notify:
+ acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
+ acpi_pcc_hotkey_notify);
+out_input:
+ input_unregister_device(pcc->input_dev);
+ /* no need to input_free_device() since core input API refcount and
+ * free()s the device */
+out_sinf:
+ kfree(pcc->sinf);
+out_hotkey:
+ kfree(pcc);
+
+ return result;
+}
+
+static int __init acpi_pcc_init(void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_init");
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ result = acpi_bus_register_driver(&acpi_pcc_driver);
+ if (result < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error registering hotkey driver\n"));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+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;
+
+ sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
+
+ backlight_device_unregister(pcc->backlight);
+
+ acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
+ acpi_pcc_hotkey_notify);
+
+ input_unregister_device(pcc->input_dev);
+ /* no need to input_free_device() since core input API refcount and
+ * free()s the device */
+
+ kfree(pcc->sinf);
+ kfree(pcc);
+
+ return 0;
+}
+
+static void __exit acpi_pcc_exit(void)
+{
+ ACPI_FUNCTION_TRACE("acpi_pcc_exit");
+
+ acpi_bus_unregister_driver(&acpi_pcc_driver);
+}
+
+module_init(acpi_pcc_init);
+module_exit(acpi_pcc_exit);
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 60775be2282..5a97d3a9d74 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -970,7 +970,7 @@ static int sony_nc_resume(struct acpi_device *device)
/* set the last requested brightness level */
if (sony_backlight_device &&
!sony_backlight_update_status(sony_backlight_device))
- printk(KERN_WARNING DRV_PFX "unable to restore brightness level");
+ printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n");
/* re-initialize models with specific requirements */
dmi_check_system(sony_nc_ids);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 6b9300779a4..4db1cf9078d 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -159,7 +159,6 @@ enum {
#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG
#define TPACPI_DBG_ALL 0xffff
-#define TPACPI_DBG_ALL 0xffff
#define TPACPI_DBG_INIT 0x0001
#define TPACPI_DBG_EXIT 0x0002
#define dbg_printk(a_dbg_level, format, arg...) \
@@ -543,7 +542,7 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
return -ENODEV;
}
- acpi_driver_data(ibm->acpi->device) = ibm;
+ ibm->acpi->device->driver_data = ibm;
sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
TPACPI_ACPI_EVENT_PREFIX,
ibm->name);
@@ -582,7 +581,8 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
if (!ibm->acpi->driver) {
- printk(TPACPI_ERR "kzalloc(ibm->driver) failed\n");
+ printk(TPACPI_ERR
+ "failed to allocate memory for ibm->acpi->driver\n");
return -ENOMEM;
}
@@ -838,6 +838,13 @@ static int parse_strtoul(const char *buf,
return 0;
}
+static void tpacpi_disable_brightness_delay(void)
+{
+ if (acpi_evalf(hkey_handle, NULL, "PWMS", "qvd", 0))
+ printk(TPACPI_NOTICE
+ "ACPI backlight control delay disabled\n");
+}
+
static int __init tpacpi_query_bcl_levels(acpi_handle handle)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -2139,6 +2146,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
if (!tp_features.hotkey)
return 1;
+ tpacpi_disable_brightness_delay();
+
hotkey_dev_attributes = create_attr_set(13, NULL);
if (!hotkey_dev_attributes)
return -ENOMEM;
@@ -2512,6 +2521,8 @@ static void hotkey_suspend(pm_message_t state)
static void hotkey_resume(void)
{
+ tpacpi_disable_brightness_delay();
+
if (hotkey_mask_get())
printk(TPACPI_ERR
"error while trying to read hot key mask "
@@ -5983,6 +5994,52 @@ static void fan_exit(void)
flush_workqueue(tpacpi_wq);
}
+static void fan_suspend(pm_message_t state)
+{
+ if (!fan_control_allowed)
+ return;
+
+ /* Store fan status in cache */
+ fan_get_status_safe(NULL);
+ if (tp_features.fan_ctrl_status_undef)
+ fan_control_desired_level = TP_EC_FAN_AUTO;
+}
+
+static void fan_resume(void)
+{
+ u8 saved_fan_level;
+ u8 current_level = 7;
+ bool do_set = false;
+
+ /* DSDT *always* updates status on resume */
+ tp_features.fan_ctrl_status_undef = 0;
+
+ saved_fan_level = fan_control_desired_level;
+ if (!fan_control_allowed ||
+ (fan_get_status_safe(&current_level) < 0))
+ return;
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ do_set = (saved_fan_level > current_level);
+ break;
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ do_set = ((saved_fan_level & TP_EC_FAN_FULLSPEED) ||
+ (saved_fan_level == 7 &&
+ !(current_level & TP_EC_FAN_FULLSPEED)));
+ break;
+ default:
+ return;
+ }
+ if (do_set) {
+ printk(TPACPI_NOTICE
+ "restoring fan level to 0x%02x\n",
+ saved_fan_level);
+ fan_set_level_safe(saved_fan_level);
+ }
+}
+
static int fan_read(char *p)
{
int len = 0;
@@ -6174,6 +6231,8 @@ static struct ibm_struct fan_driver_data = {
.read = fan_read,
.write = fan_write,
.exit = fan_exit,
+ .suspend = fan_suspend,
+ .resume = fan_resume,
};
/****************************************************************************
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 24c97d3d16b..3d067c35185 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -92,18 +92,17 @@ static void mmc_blk_put(struct mmc_blk_data *md)
mutex_unlock(&open_lock);
}
-static int mmc_blk_open(struct inode *inode, struct file *filp)
+static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
- struct mmc_blk_data *md;
+ struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
int ret = -ENXIO;
- md = mmc_blk_get(inode->i_bdev->bd_disk);
if (md) {
if (md->usage == 2)
- check_disk_change(inode->i_bdev);
+ check_disk_change(bdev);
ret = 0;
- if ((filp->f_mode & FMODE_WRITE) && md->read_only) {
+ if ((mode & FMODE_WRITE) && md->read_only) {
mmc_blk_put(md);
ret = -EROFS;
}
@@ -112,9 +111,9 @@ static int mmc_blk_open(struct inode *inode, struct file *filp)
return ret;
}
-static int mmc_blk_release(struct inode *inode, struct file *filp)
+static int mmc_blk_release(struct gendisk *disk, fmode_t mode)
{
- struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;
+ struct mmc_blk_data *md = disk->private_data;
mmc_blk_put(md);
return 0;
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 406989e992b..7a72e75d5c6 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -132,6 +132,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_prep_rq(mq->queue, mmc_prep_request);
blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
#ifdef CONFIG_MMC_BLOCK_BOUNCE
if (host->max_hw_segs == 1) {
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index ae16d845d74..3b2085b5776 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -3,6 +3,9 @@
*
* Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de>
*
+ * Current driver maintained by Ben Dooks and Simtec Electronics
+ * Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org>
+ *
* 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.
@@ -13,6 +16,7 @@
#include <linux/clk.h>
#include <linux/mmc/host.h>
#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
#include <linux/irq.h>
#include <linux/io.h>
@@ -39,9 +43,9 @@ enum dbg_channels {
dbg_conf = (1 << 8),
};
-static const int dbgmap_err = dbg_err | dbg_fail;
+static const int dbgmap_err = dbg_fail;
static const int dbgmap_info = dbg_info | dbg_conf;
-static const int dbgmap_debug = dbg_debug;
+static const int dbgmap_debug = dbg_err | dbg_debug;
#define dbg(host, channels, args...) \
do { \
@@ -189,7 +193,7 @@ static inline void clear_imask(struct s3cmci_host *host)
}
static inline int get_data_buffer(struct s3cmci_host *host,
- u32 *words, u32 **pointer)
+ u32 *bytes, u32 **pointer)
{
struct scatterlist *sg;
@@ -206,7 +210,7 @@ static inline int get_data_buffer(struct s3cmci_host *host,
}
sg = &host->mrq->data->sg[host->pio_sgptr];
- *words = sg->length >> 2;
+ *bytes = sg->length;
*pointer = sg_virt(sg);
host->pio_sgptr++;
@@ -222,7 +226,7 @@ static inline u32 fifo_count(struct s3cmci_host *host)
u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
fifostat &= S3C2410_SDIFSTA_COUNTMASK;
- return fifostat >> 2;
+ return fifostat;
}
static inline u32 fifo_free(struct s3cmci_host *host)
@@ -230,13 +234,15 @@ static inline u32 fifo_free(struct s3cmci_host *host)
u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
fifostat &= S3C2410_SDIFSTA_COUNTMASK;
- return (63 - fifostat) >> 2;
+ return 63 - fifostat;
}
static void do_pio_read(struct s3cmci_host *host)
{
int res;
u32 fifo;
+ u32 *ptr;
+ u32 fifo_words;
void __iomem *from_ptr;
/* write real prescaler to host, it might be set slow to fix */
@@ -245,8 +251,8 @@ static void do_pio_read(struct s3cmci_host *host)
from_ptr = host->base + host->sdidata;
while ((fifo = fifo_count(host))) {
- if (!host->pio_words) {
- res = get_data_buffer(host, &host->pio_words,
+ if (!host->pio_bytes) {
+ res = get_data_buffer(host, &host->pio_bytes,
&host->pio_ptr);
if (res) {
host->pio_active = XFER_NONE;
@@ -259,26 +265,47 @@ static void do_pio_read(struct s3cmci_host *host)
dbg(host, dbg_pio,
"pio_read(): new target: [%i]@[%p]\n",
- host->pio_words, host->pio_ptr);
+ host->pio_bytes, host->pio_ptr);
}
dbg(host, dbg_pio,
"pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n",
- fifo, host->pio_words,
+ fifo, host->pio_bytes,
readl(host->base + S3C2410_SDIDCNT));
- if (fifo > host->pio_words)
- fifo = host->pio_words;
+ /* If we have reached the end of the block, we can
+ * read a word and get 1 to 3 bytes. If we in the
+ * middle of the block, we have to read full words,
+ * otherwise we will write garbage, so round down to
+ * an even multiple of 4. */
+ if (fifo >= host->pio_bytes)
+ fifo = host->pio_bytes;
+ else
+ fifo -= fifo & 3;
- host->pio_words -= fifo;
+ host->pio_bytes -= fifo;
host->pio_count += fifo;
- while (fifo--)
- *(host->pio_ptr++) = readl(from_ptr);
+ fifo_words = fifo >> 2;
+ ptr = host->pio_ptr;
+ while (fifo_words--)
+ *ptr++ = readl(from_ptr);
+ host->pio_ptr = ptr;
+
+ if (fifo & 3) {
+ u32 n = fifo & 3;
+ u32 data = readl(from_ptr);
+ u8 *p = (u8 *)host->pio_ptr;
+
+ while (n--) {
+ *p++ = data;
+ data >>= 8;
+ }
+ }
}
- if (!host->pio_words) {
- res = get_data_buffer(host, &host->pio_words, &host->pio_ptr);
+ if (!host->pio_bytes) {
+ res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr);
if (res) {
dbg(host, dbg_pio,
"pio_read(): complete (no more buffers).\n");
@@ -298,12 +325,13 @@ static void do_pio_write(struct s3cmci_host *host)
void __iomem *to_ptr;
int res;
u32 fifo;
+ u32 *ptr;
to_ptr = host->base + host->sdidata;
while ((fifo = fifo_free(host))) {
- if (!host->pio_words) {
- res = get_data_buffer(host, &host->pio_words,
+ if (!host->pio_bytes) {
+ res = get_data_buffer(host, &host->pio_bytes,
&host->pio_ptr);
if (res) {
dbg(host, dbg_pio,
@@ -315,18 +343,27 @@ static void do_pio_write(struct s3cmci_host *host)
dbg(host, dbg_pio,
"pio_write(): new source: [%i]@[%p]\n",
- host->pio_words, host->pio_ptr);
+ host->pio_bytes, host->pio_ptr);
}
- if (fifo > host->pio_words)
- fifo = host->pio_words;
+ /* If we have reached the end of the block, we have to
+ * write exactly the remaining number of bytes. If we
+ * in the middle of the block, we have to write full
+ * words, so round down to an even multiple of 4. */
+ if (fifo >= host->pio_bytes)
+ fifo = host->pio_bytes;
+ else
+ fifo -= fifo & 3;
- host->pio_words -= fifo;
+ host->pio_bytes -= fifo;
host->pio_count += fifo;
+ fifo = (fifo + 3) >> 2;
+ ptr = host->pio_ptr;
while (fifo--)
- writel(*(host->pio_ptr++), to_ptr);
+ writel(*ptr++, to_ptr);
+ host->pio_ptr = ptr;
}
enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
@@ -349,9 +386,9 @@ static void pio_tasklet(unsigned long data)
clear_imask(host);
if (host->pio_active != XFER_NONE) {
dbg(host, dbg_err, "unfinished %s "
- "- pio_count:[%u] pio_words:[%u]\n",
+ "- pio_count:[%u] pio_bytes:[%u]\n",
(host->pio_active == XFER_READ) ? "read" : "write",
- host->pio_count, host->pio_words);
+ host->pio_count, host->pio_bytes);
if (host->mrq->data)
host->mrq->data->error = -EINVAL;
@@ -812,11 +849,10 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
/* We cannot deal with unaligned blocks with more than
* one block being transfered. */
- if (data->blocks > 1)
+ if (data->blocks > 1) {
+ pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz);
return -EINVAL;
-
- /* No support yet for non-word block transfers. */
- return -EINVAL;
+ }
}
while (readl(host->base + S3C2410_SDIDSTA) &
@@ -896,7 +932,7 @@ static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data)
BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
host->pio_sgptr = 0;
- host->pio_words = 0;
+ host->pio_bytes = 0;
host->pio_count = 0;
host->pio_active = rw ? XFER_WRITE : XFER_READ;
@@ -1033,10 +1069,33 @@ static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
s3cmci_send_request(mmc);
}
+static void s3cmci_set_clk(struct s3cmci_host *host, struct mmc_ios *ios)
+{
+ u32 mci_psc;
+
+ /* Set clock */
+ for (mci_psc = 0; mci_psc < 255; mci_psc++) {
+ host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
+
+ if (host->real_rate <= ios->clock)
+ break;
+ }
+
+ if (mci_psc > 255)
+ mci_psc = 255;
+
+ host->prescaler = mci_psc;
+ writel(host->prescaler, host->base + S3C2410_SDIPRE);
+
+ /* If requested clock is 0, real_rate will be 0, too */
+ if (ios->clock == 0)
+ host->real_rate = 0;
+}
+
static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct s3cmci_host *host = mmc_priv(mmc);
- u32 mci_psc, mci_con;
+ u32 mci_con;
/* Set the power state */
@@ -1074,23 +1133,7 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break;
}
- /* Set clock */
- for (mci_psc = 0; mci_psc < 255; mci_psc++) {
- host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
-
- if (host->real_rate <= ios->clock)
- break;
- }
-
- if (mci_psc > 255)
- mci_psc = 255;
-
- host->prescaler = mci_psc;
- writel(host->prescaler, host->base + S3C2410_SDIPRE);
-
- /* If requested clock is 0, real_rate will be 0, too */
- if (ios->clock == 0)
- host->real_rate = 0;
+ s3cmci_set_clk(host, ios);
/* Set CLOCK_ENABLE */
if (ios->clock)
@@ -1148,6 +1191,61 @@ static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
* checks. Any zero fields to ensure reaonable defaults are picked. */
};
+#ifdef CONFIG_CPU_FREQ
+
+static int s3cmci_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct s3cmci_host *host;
+ struct mmc_host *mmc;
+ unsigned long newclk;
+ unsigned long flags;
+
+ host = container_of(nb, struct s3cmci_host, freq_transition);
+ newclk = clk_get_rate(host->clk);
+ mmc = host->mmc;
+
+ if ((val == CPUFREQ_PRECHANGE && newclk > host->clk_rate) ||
+ (val == CPUFREQ_POSTCHANGE && newclk < host->clk_rate)) {
+ spin_lock_irqsave(&mmc->lock, flags);
+
+ host->clk_rate = newclk;
+
+ if (mmc->ios.power_mode != MMC_POWER_OFF &&
+ mmc->ios.clock != 0)
+ s3cmci_set_clk(host, &mmc->ios);
+
+ spin_unlock_irqrestore(&mmc->lock, flags);
+ }
+
+ return 0;
+}
+
+static inline int s3cmci_cpufreq_register(struct s3cmci_host *host)
+{
+ host->freq_transition.notifier_call = s3cmci_cpufreq_transition;
+
+ return cpufreq_register_notifier(&host->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host)
+{
+ cpufreq_unregister_notifier(&host->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3cmci_cpufreq_register(struct s3cmci_host *host)
+{
+ return 0;
+}
+
+static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host)
+{
+}
+#endif
+
static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
{
struct s3cmci_host *host;
@@ -1298,10 +1396,16 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
(host->is2440?"2440":""),
host->base, host->irq, host->irq_cd, host->dma);
+ ret = s3cmci_cpufreq_register(host);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register cpufreq\n");
+ goto free_dmabuf;
+ }
+
ret = mmc_add_host(mmc);
if (ret) {
dev_err(&pdev->dev, "failed to add mmc host.\n");
- goto free_dmabuf;
+ goto free_cpufreq;
}
platform_set_drvdata(pdev, mmc);
@@ -1309,6 +1413,9 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
return 0;
+ free_cpufreq:
+ s3cmci_cpufreq_deregister(host);
+
free_dmabuf:
clk_disable(host->clk);
@@ -1342,6 +1449,7 @@ static void s3cmci_shutdown(struct platform_device *pdev)
if (host->irq_cd >= 0)
free_irq(host->irq_cd, host);
+ s3cmci_cpufreq_deregister(host);
mmc_remove_host(mmc);
clk_disable(host->clk);
}
@@ -1455,7 +1563,7 @@ module_exit(s3cmci_exit);
MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>");
+MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>");
MODULE_ALIAS("platform:s3c2410-sdi");
MODULE_ALIAS("platform:s3c2412-sdi");
MODULE_ALIAS("platform:s3c2440-sdi");
diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h
index 37d9c60010c..ca1ba3d58cf 100644
--- a/drivers/mmc/host/s3cmci.h
+++ b/drivers/mmc/host/s3cmci.h
@@ -51,7 +51,7 @@ struct s3cmci_host {
int dma_complete;
u32 pio_sgptr;
- u32 pio_words;
+ u32 pio_bytes;
u32 pio_count;
u32 *pio_ptr;
#define XFER_NONE 0
@@ -67,4 +67,8 @@ struct s3cmci_host {
unsigned int ccnt, dcnt;
struct tasklet_struct pio_tasklet;
+
+#ifdef CONFIG_CPU_FREQ
+ struct notifier_block freq_transition;
+#endif
};
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 14f11f8b9e5..a90d50c2c3e 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -172,6 +172,11 @@ config MTD_CHAR
memory chips, and also use ioctl() to obtain information about
the device, or to erase parts of it.
+config HAVE_MTD_OTP
+ bool
+ help
+ Enable access to OTP regions using MTD_CHAR.
+
config MTD_BLKDEVS
tristate "Common interface to block layer for MTD 'translation layers'"
depends on BLOCK
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 479d32b57a1..9408099eec4 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -6,6 +6,7 @@ menu "RAM/ROM/Flash chip drivers"
config MTD_CFI
tristate "Detect flash chips by Common Flash Interface (CFI) probe"
select MTD_GEN_PROBE
+ select MTD_CFI_UTIL
help
The Common Flash Interface specification was developed by Intel,
AMD and other flash manufactures that provides a universal method
@@ -154,6 +155,7 @@ config MTD_CFI_I8
config MTD_OTP
bool "Protection Registers aka one-time programmable (OTP) bits"
depends on MTD_CFI_ADV_OPTIONS
+ select HAVE_MTD_OTP
default n
help
This enables support for reading, writing and locking so called
@@ -187,7 +189,7 @@ config MTD_CFI_INTELEXT
StrataFlash and other parts.
config MTD_CFI_AMDSTD
- tristate "Support for AMD/Fujitsu flash chips"
+ tristate "Support for AMD/Fujitsu/Spansion flash chips"
depends on MTD_GEN_PROBE
select MTD_CFI_UTIL
help
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 5f1b472137a..c93a8be5d5f 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -478,6 +478,28 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
else
cfi->chips[i].erase_time = 2000000;
+ if (cfi->cfiq->WordWriteTimeoutTyp &&
+ cfi->cfiq->WordWriteTimeoutMax)
+ cfi->chips[i].word_write_time_max =
+ 1<<(cfi->cfiq->WordWriteTimeoutTyp +
+ cfi->cfiq->WordWriteTimeoutMax);
+ else
+ cfi->chips[i].word_write_time_max = 50000 * 8;
+
+ if (cfi->cfiq->BufWriteTimeoutTyp &&
+ cfi->cfiq->BufWriteTimeoutMax)
+ cfi->chips[i].buffer_write_time_max =
+ 1<<(cfi->cfiq->BufWriteTimeoutTyp +
+ cfi->cfiq->BufWriteTimeoutMax);
+
+ if (cfi->cfiq->BlockEraseTimeoutTyp &&
+ cfi->cfiq->BlockEraseTimeoutMax)
+ cfi->chips[i].erase_time_max =
+ 1000<<(cfi->cfiq->BlockEraseTimeoutTyp +
+ cfi->cfiq->BlockEraseTimeoutMax);
+ else
+ cfi->chips[i].erase_time_max = 2000000 * 8;
+
cfi->chips[i].ref_point_counter = 0;
init_waitqueue_head(&(cfi->chips[i].wq));
}
@@ -703,6 +725,10 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
unsigned long timeo = jiffies + HZ;
+ /* Prevent setting state FL_SYNCING for chip in suspended state. */
+ if (mode == FL_SYNCING && chip->oldstate != FL_READY)
+ goto sleep;
+
switch (chip->state) {
case FL_STATUS:
@@ -808,8 +834,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
DECLARE_WAITQUEUE(wait, current);
retry:
- if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
- || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
+ if (chip->priv &&
+ (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE
+ || mode == FL_SHUTDOWN) && chip->state != FL_SYNCING) {
/*
* OK. We have possibility for contention on the write/erase
* operations which are global to the real chip and not per
@@ -859,6 +886,14 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
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, contender->start);
+ spin_unlock(contender->mutex);
+ goto retry;
+ }
spin_unlock(contender->mutex);
}
@@ -1012,7 +1047,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
static int __xipram xip_wait_for_operation(
struct map_info *map, struct flchip *chip,
- unsigned long adr, unsigned int chip_op_time )
+ unsigned long adr, unsigned int chip_op_time_max)
{
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
@@ -1021,7 +1056,7 @@ static int __xipram xip_wait_for_operation(
flstate_t oldstate, newstate;
start = xip_currtime();
- usec = chip_op_time * 8;
+ usec = chip_op_time_max;
if (usec == 0)
usec = 500000;
done = 0;
@@ -1131,8 +1166,8 @@ static int __xipram xip_wait_for_operation(
#define XIP_INVAL_CACHED_RANGE(map, from, size) \
INVALIDATE_CACHED_RANGE(map, from, size)
-#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \
- xip_wait_for_operation(map, chip, cmd_adr, usec)
+#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec, usec_max) \
+ xip_wait_for_operation(map, chip, cmd_adr, usec_max)
#else
@@ -1144,7 +1179,7 @@ static int __xipram xip_wait_for_operation(
static int inval_cache_and_wait_for_operation(
struct map_info *map, struct flchip *chip,
unsigned long cmd_adr, unsigned long inval_adr, int inval_len,
- unsigned int chip_op_time)
+ unsigned int chip_op_time, unsigned int chip_op_time_max)
{
struct cfi_private *cfi = map->fldrv_priv;
map_word status, status_OK = CMD(0x80);
@@ -1156,8 +1191,7 @@ static int inval_cache_and_wait_for_operation(
INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);
spin_lock(chip->mutex);
- /* set our timeout to 8 times the expected delay */
- timeo = chip_op_time * 8;
+ timeo = chip_op_time_max;
if (!timeo)
timeo = 500000;
reset_timeo = timeo;
@@ -1217,8 +1251,8 @@ static int inval_cache_and_wait_for_operation(
#endif
-#define WAIT_TIMEOUT(map, chip, adr, udelay) \
- INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay);
+#define WAIT_TIMEOUT(map, chip, adr, udelay, udelay_max) \
+ INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay, udelay_max);
static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
@@ -1452,7 +1486,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
adr, map_bankwidth(map),
- chip->word_write_time);
+ chip->word_write_time,
+ chip->word_write_time_max);
if (ret) {
xip_enable(map, chip, adr);
printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
@@ -1623,7 +1658,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
chip->state = FL_WRITING_TO_BUFFER;
map_write(map, write_cmd, cmd_adr);
- ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0);
+ ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0, 0);
if (ret) {
/* Argh. Not ready for write to buffer */
map_word Xstatus = map_read(map, cmd_adr);
@@ -1640,7 +1675,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
/* 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);
+ words = DIV_ROUND_UP(len - word_gap, map_bankwidth(map));
if (!word_gap) {
words--;
} else {
@@ -1692,7 +1727,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
initial_adr, initial_len,
- chip->buffer_write_time);
+ chip->buffer_write_time,
+ chip->buffer_write_time_max);
if (ret) {
map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS;
@@ -1827,7 +1863,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
adr, len,
- chip->erase_time);
+ chip->erase_time,
+ chip->erase_time_max);
if (ret) {
map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
@@ -2006,7 +2043,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
*/
udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;
- ret = WAIT_TIMEOUT(map, chip, adr, udelay);
+ ret = WAIT_TIMEOUT(map, chip, adr, udelay, udelay * 100);
if (ret) {
map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index a972cc6be43..3e6f5d8609e 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -13,6 +13,8 @@
* XIP support hooks by Vitaly Wool (based on code for Intel flash
* by Nicolas Pitre)
*
+ * 25/09/2008 Christopher Moore: TopBottom fixup for many Macronix with CFI V1.0
+ *
* Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
*
* This code is GPL
@@ -43,6 +45,7 @@
#define MANUFACTURER_AMD 0x0001
#define MANUFACTURER_ATMEL 0x001F
+#define MANUFACTURER_MACRONIX 0x00C2
#define MANUFACTURER_SST 0x00BF
#define SST49LF004B 0x0060
#define SST49LF040B 0x0050
@@ -144,12 +147,44 @@ static void fixup_amd_bootblock(struct mtd_info *mtd, void* param)
if (((major << 8) | minor) < 0x3131) {
/* CFI version 1.0 => don't trust bootloc */
+
+ DEBUG(MTD_DEBUG_LEVEL1,
+ "%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n",
+ map->name, cfi->mfr, cfi->id);
+
+ /* AFAICS all 29LV400 with a bottom boot block have a device ID
+ * of 0x22BA in 16-bit mode and 0xBA in 8-bit mode.
+ * These were badly detected as they have the 0x80 bit set
+ * so treat them as a special case.
+ */
+ if (((cfi->id == 0xBA) || (cfi->id == 0x22BA)) &&
+
+ /* Macronix added CFI to their 2nd generation
+ * MX29LV400C B/T but AFAICS no other 29LV400 (AMD,
+ * Fujitsu, Spansion, EON, ESI and older Macronix)
+ * has CFI.
+ *
+ * Therefore also check the manufacturer.
+ * This reduces the risk of false detection due to
+ * the 8-bit device ID.
+ */
+ (cfi->mfr == MANUFACTURER_MACRONIX)) {
+ DEBUG(MTD_DEBUG_LEVEL1,
+ "%s: Macronix MX29LV400C with bottom boot block"
+ " detected\n", map->name);
+ extp->TopBottom = 2; /* bottom boot */
+ } else
if (cfi->id & 0x80) {
printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
extp->TopBottom = 3; /* top boot */
} else {
extp->TopBottom = 2; /* bottom boot */
}
+
+ DEBUG(MTD_DEBUG_LEVEL1,
+ "%s: AMD CFI PRI V%c.%c has no boot block field;"
+ " deduced %s from Device ID\n", map->name, major, minor,
+ extp->TopBottom == 2 ? "bottom" : "top");
}
}
#endif
@@ -178,10 +213,18 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
if (atmel_pri.Features & 0x02)
extp->EraseSuspend = 2;
- if (atmel_pri.BottomBoot)
- extp->TopBottom = 2;
- else
- extp->TopBottom = 3;
+ /* Some chips got it backwards... */
+ if (cfi->id == AT49BV6416) {
+ if (atmel_pri.BottomBoot)
+ extp->TopBottom = 3;
+ else
+ extp->TopBottom = 2;
+ } else {
+ if (atmel_pri.BottomBoot)
+ extp->TopBottom = 2;
+ else
+ extp->TopBottom = 3;
+ }
/* burst write mode not supported */
cfi->cfiq->BufWriteTimeoutTyp = 0;
@@ -243,6 +286,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
#ifdef AMD_BOOTLOC_BUG
{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
+ { MANUFACTURER_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock, NULL },
#endif
{ CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, },
{ CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, },
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c
index c418e92e1d9..e63e6749429 100644
--- a/drivers/mtd/chips/cfi_probe.c
+++ b/drivers/mtd/chips/cfi_probe.c
@@ -44,17 +44,14 @@ do { \
#define xip_enable(base, map, cfi) \
do { \
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
+ cfi_qry_mode_off(base, map, cfi); \
xip_allowed(base, map); \
} while (0)
#define xip_disable_qry(base, map, cfi) \
do { \
xip_disable(); \
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); \
+ cfi_qry_mode_on(base, map, cfi); \
} while (0)
#else
@@ -70,32 +67,6 @@ do { \
in: interleave,type,mode
ret: table index, <0 for error
*/
-static int __xipram qry_present(struct map_info *map, __u32 base,
- struct cfi_private *cfi)
-{
- int osf = cfi->interleave * cfi->device_type; // scale factor
- map_word val[3];
- map_word qry[3];
-
- qry[0] = cfi_build_cmd('Q', map, cfi);
- qry[1] = cfi_build_cmd('R', map, cfi);
- qry[2] = cfi_build_cmd('Y', map, cfi);
-
- val[0] = map_read(map, base + osf*0x10);
- val[1] = map_read(map, base + osf*0x11);
- val[2] = map_read(map, base + osf*0x12);
-
- if (!map_word_equal(map, qry[0], val[0]))
- return 0;
-
- if (!map_word_equal(map, qry[1], val[1]))
- return 0;
-
- if (!map_word_equal(map, qry[2], val[2]))
- return 0;
-
- return 1; // "QRY" found
-}
static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
unsigned long *chip_map, struct cfi_private *cfi)
@@ -116,11 +87,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
}
xip_disable();
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
- if (!qry_present(map,base,cfi)) {
+ if (!cfi_qry_mode_on(base, map, cfi)) {
xip_enable(base, map, cfi);
return 0;
}
@@ -141,14 +108,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
start = i << cfi->chipshift;
/* This chip should be in read mode if it's one
we've already touched. */
- if (qry_present(map, start, cfi)) {
+ if (cfi_qry_present(map, start, cfi)) {
/* Eep. This chip also had the QRY marker.
* Is it an alias for the new one? */
- cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
+ cfi_qry_mode_off(start, map, cfi);
/* If the QRY marker goes away, it's an alias */
- if (!qry_present(map, start, cfi)) {
+ if (!cfi_qry_present(map, start, cfi)) {
xip_allowed(base, map);
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
map->name, base, start);
@@ -158,10 +124,9 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
* unfortunate. Stick the new chip in read mode
* too and if it's the same, assume it's an alias. */
/* FIXME: Use other modes to do a proper check */
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
+ cfi_qry_mode_off(base, map, cfi);
- if (qry_present(map, base, cfi)) {
+ if (cfi_qry_present(map, base, cfi)) {
xip_allowed(base, map);
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
map->name, base, start);
@@ -176,8 +141,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
cfi->numchips++;
/* Put it back into Read Mode */
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_qry_mode_off(base, map, cfi);
xip_allowed(base, map);
printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
@@ -237,9 +201,7 @@ static int __xipram cfi_chip_setup(struct map_info *map,
cfi_read_query(map, base + 0xf * ofs_factor);
/* Put it back into Read Mode */
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
- /* ... even if it's an Intel chip */
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_qry_mode_off(base, map, cfi);
xip_allowed(base, map);
/* Do any necessary byteswapping */
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
index 0ee45701801..34d40e25d31 100644
--- a/drivers/mtd/chips/cfi_util.c
+++ b/drivers/mtd/chips/cfi_util.c
@@ -24,6 +24,66 @@
#include <linux/mtd/cfi.h>
#include <linux/mtd/compatmac.h>
+int __xipram cfi_qry_present(struct map_info *map, __u32 base,
+ struct cfi_private *cfi)
+{
+ int osf = cfi->interleave * cfi->device_type; /* scale factor */
+ map_word val[3];
+ map_word qry[3];
+
+ qry[0] = cfi_build_cmd('Q', map, cfi);
+ qry[1] = cfi_build_cmd('R', map, cfi);
+ qry[2] = cfi_build_cmd('Y', map, cfi);
+
+ val[0] = map_read(map, base + osf*0x10);
+ val[1] = map_read(map, base + osf*0x11);
+ val[2] = map_read(map, base + osf*0x12);
+
+ if (!map_word_equal(map, qry[0], val[0]))
+ return 0;
+
+ if (!map_word_equal(map, qry[1], val[1]))
+ return 0;
+
+ if (!map_word_equal(map, qry[2], val[2]))
+ return 0;
+
+ return 1; /* "QRY" found */
+}
+EXPORT_SYMBOL_GPL(cfi_qry_present);
+
+int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map,
+ struct cfi_private *cfi)
+{
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+ if (cfi_qry_present(map, base, cfi))
+ return 1;
+ /* QRY not found probably we deal with some odd CFI chips */
+ /* Some revisions of some old Intel chips? */
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+ if (cfi_qry_present(map, base, cfi))
+ return 1;
+ /* ST M29DW chips */
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
+ if (cfi_qry_present(map, base, cfi))
+ return 1;
+ /* QRY not found */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cfi_qry_mode_on);
+
+void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map,
+ struct cfi_private *cfi)
+{
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+}
+EXPORT_SYMBOL_GPL(cfi_qry_mode_off);
+
struct cfi_extquery *
__xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
{
@@ -48,8 +108,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n
#endif
/* Switch it into Query Mode */
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
+ cfi_qry_mode_on(base, map, cfi);
/* Read in the Extended Query Table */
for (i=0; i<size; i++) {
((unsigned char *)extp)[i] =
@@ -57,8 +116,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n
}
/* Make sure it returns to read mode */
- cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_qry_mode_off(base, map, cfi);
#ifdef CONFIG_MTD_XIP
(void) map_read(map, base);
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c
index f061885b281..e2dc96441e0 100644
--- a/drivers/mtd/chips/gen_probe.c
+++ b/drivers/mtd/chips/gen_probe.c
@@ -111,7 +111,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
max_chips = 1;
}
- mapsize = sizeof(long) * ( (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG );
+ mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG);
chip_map = kzalloc(mapsize, GFP_KERNEL);
if (!chip_map) {
printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index 71bc07f149b..50a340388e7 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -7,6 +7,7 @@
*
* mtdparts=<mtddef>[;<mtddef]
* <mtddef> := <mtd-id>:<partdef>[,<partdef>]
+ * where <mtd-id> is the name from the "cat /proc/mtd" command
* <partdef> := <size>[@offset][<name>][ro][lk]
* <mtd-id> := unique name used in mapping driver/device (mtd->name)
* <size> := standard linux memsize OR "-" to denote all remaining space
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 9c613f06623..6fde0a2e356 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -59,6 +59,27 @@ config MTD_DATAFLASH
Sometimes DataFlash chips are packaged inside MMC-format
cards; at this writing, the MMC stack won't handle those.
+config MTD_DATAFLASH_WRITE_VERIFY
+ bool "Verify DataFlash page writes"
+ depends on MTD_DATAFLASH
+ help
+ This adds an extra check when data is written to the flash.
+ It may help if you are verifying chip setup (timings etc) on
+ your board. There is a rare possibility that even though the
+ device thinks the write was successful, a bit could have been
+ flipped accidentally due to device wear or something else.
+
+config MTD_DATAFLASH_OTP
+ bool "DataFlash OTP support (Security Register)"
+ depends on MTD_DATAFLASH
+ select HAVE_MTD_OTP
+ help
+ Newer DataFlash chips (revisions C and D) support 128 bytes of
+ one-time-programmable (OTP) data. The first half may be written
+ (once) with up to 64 bytes of data, such as a serial number or
+ other key product data. The second half is programmed with a
+ unique-to-each-chip bit pattern at the factory.
+
config MTD_M25P80
tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
depends on SPI_MASTER && EXPERIMENTAL
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 91fbba76763..8c295f40d2a 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -224,7 +224,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
if (dev->blkdev) {
invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
0, -1);
- close_bdev_excl(dev->blkdev);
+ close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
}
kfree(dev);
@@ -246,7 +246,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
return NULL;
/* Get a handle on the device */
- bdev = open_bdev_excl(devname, O_RDWR, NULL);
+ bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, NULL);
#ifndef MODULE
if (IS_ERR(bdev)) {
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index b35c3333e21..76a76751da3 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -39,6 +39,7 @@
#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */
+#define OPCODE_BE 0xc7 /* Erase whole flash block */
#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */
@@ -161,6 +162,31 @@ static int wait_till_ready(struct m25p *flash)
return 1;
}
+/*
+ * Erase the whole flash memory
+ *
+ * Returns 0 if successful, non-zero otherwise.
+ */
+static int erase_block(struct m25p *flash)
+{
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB\n",
+ flash->spi->dev.bus_id, __func__,
+ flash->mtd.size / 1024);
+
+ /* Wait until finished previous write command. */
+ if (wait_till_ready(flash))
+ return 1;
+
+ /* Send write enable, then erase commands. */
+ write_enable(flash);
+
+ /* Set up command buffer. */
+ flash->command[0] = OPCODE_BE;
+
+ spi_write(flash->spi, flash->command, 1);
+
+ return 0;
+}
/*
* Erase one sector of flash memory at offset ``offset'' which is any
@@ -229,15 +255,21 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
*/
/* now erase those sectors */
- while (len) {
- if (erase_sector(flash, addr)) {
- instr->state = MTD_ERASE_FAILED;
- mutex_unlock(&flash->lock);
- return -EIO;
- }
+ if (len == flash->mtd.size && erase_block(flash)) {
+ instr->state = MTD_ERASE_FAILED;
+ mutex_unlock(&flash->lock);
+ return -EIO;
+ } else {
+ while (len) {
+ if (erase_sector(flash, addr)) {
+ instr->state = MTD_ERASE_FAILED;
+ mutex_unlock(&flash->lock);
+ return -EIO;
+ }
- addr += mtd->erasesize;
- len -= mtd->erasesize;
+ addr += mtd->erasesize;
+ len -= mtd->erasesize;
+ }
}
mutex_unlock(&flash->lock);
@@ -437,6 +469,7 @@ struct flash_info {
* then a two byte device id.
*/
u32 jedec_id;
+ u16 ext_id;
/* The size listed here is what works with OPCODE_SE, which isn't
* necessarily called a "sector" by the vendor.
@@ -456,72 +489,75 @@ struct flash_info {
static struct flash_info __devinitdata m25p_data [] = {
/* Atmel -- some are (confusingly) marketed as "DataFlash" */
- { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, },
- { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, },
+ { "at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K, },
+ { "at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K, },
- { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, },
- { "at25df641", 0x1f4800, 64 * 1024, 128, SECT_4K, },
+ { "at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K, },
+ { "at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K, },
- { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, },
- { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, },
- { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, },
- { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, },
+ { "at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K, },
+ { "at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K, },
+ { "at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K, },
+ { "at26df321", 0x1f4701, 0, 64 * 1024, 64, SECT_4K, },
/* Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
*/
- { "s25sl004a", 0x010212, 64 * 1024, 8, },
- { "s25sl008a", 0x010213, 64 * 1024, 16, },
- { "s25sl016a", 0x010214, 64 * 1024, 32, },
- { "s25sl032a", 0x010215, 64 * 1024, 64, },
- { "s25sl064a", 0x010216, 64 * 1024, 128, },
+ { "s25sl004a", 0x010212, 0, 64 * 1024, 8, },
+ { "s25sl008a", 0x010213, 0, 64 * 1024, 16, },
+ { "s25sl016a", 0x010214, 0, 64 * 1024, 32, },
+ { "s25sl032a", 0x010215, 0, 64 * 1024, 64, },
+ { "s25sl064a", 0x010216, 0, 64 * 1024, 128, },
+ { "s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, },
+ { "s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, },
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
- { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, },
- { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, },
- { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, },
- { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, },
+ { "sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K, },
+ { "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K, },
+ { "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K, },
+ { "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K, },
/* ST Microelectronics -- newer production may have feature updates */
- { "m25p05", 0x202010, 32 * 1024, 2, },
- { "m25p10", 0x202011, 32 * 1024, 4, },
- { "m25p20", 0x202012, 64 * 1024, 4, },
- { "m25p40", 0x202013, 64 * 1024, 8, },
- { "m25p80", 0, 64 * 1024, 16, },
- { "m25p16", 0x202015, 64 * 1024, 32, },
- { "m25p32", 0x202016, 64 * 1024, 64, },
- { "m25p64", 0x202017, 64 * 1024, 128, },
- { "m25p128", 0x202018, 256 * 1024, 64, },
-
- { "m45pe80", 0x204014, 64 * 1024, 16, },
- { "m45pe16", 0x204015, 64 * 1024, 32, },
-
- { "m25pe80", 0x208014, 64 * 1024, 16, },
- { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, },
+ { "m25p05", 0x202010, 0, 32 * 1024, 2, },
+ { "m25p10", 0x202011, 0, 32 * 1024, 4, },
+ { "m25p20", 0x202012, 0, 64 * 1024, 4, },
+ { "m25p40", 0x202013, 0, 64 * 1024, 8, },
+ { "m25p80", 0, 0, 64 * 1024, 16, },
+ { "m25p16", 0x202015, 0, 64 * 1024, 32, },
+ { "m25p32", 0x202016, 0, 64 * 1024, 64, },
+ { "m25p64", 0x202017, 0, 64 * 1024, 128, },
+ { "m25p128", 0x202018, 0, 256 * 1024, 64, },
+
+ { "m45pe80", 0x204014, 0, 64 * 1024, 16, },
+ { "m45pe16", 0x204015, 0, 64 * 1024, 32, },
+
+ { "m25pe80", 0x208014, 0, 64 * 1024, 16, },
+ { "m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K, },
/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
- { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, },
- { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, },
- { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, },
- { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, },
- { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, },
- { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, },
- { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, },
+ { "w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K, },
+ { "w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K, },
+ { "w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K, },
+ { "w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K, },
+ { "w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K, },
+ { "w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K, },
+ { "w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K, },
};
static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
{
int tmp;
u8 code = OPCODE_RDID;
- u8 id[3];
+ u8 id[5];
u32 jedec;
+ u16 ext_jedec;
struct flash_info *info;
/* JEDEC also defines an optional "extended device information"
* string for after vendor-specific data, after the three bytes
* we use here. Supporting some chips might require using it.
*/
- tmp = spi_write_then_read(spi, &code, 1, id, 3);
+ tmp = spi_write_then_read(spi, &code, 1, id, 5);
if (tmp < 0) {
DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n",
spi->dev.bus_id, tmp);
@@ -533,10 +569,14 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
jedec = jedec << 8;
jedec |= id[2];
+ ext_jedec = id[3] << 8 | id[4];
+
for (tmp = 0, info = m25p_data;
tmp < ARRAY_SIZE(m25p_data);
tmp++, info++) {
if (info->jedec_id == jedec)
+ if (ext_jedec != 0 && info->ext_id != ext_jedec)
+ continue;
return info;
}
dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 8bd0dea6885..6dd9aff8bb2 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -30,12 +30,10 @@
* doesn't (yet) use these for any kind of i/o overlap or prefetching.
*
* Sometimes DataFlash is packaged in MMC-format cards, although the
- * MMC stack can't use SPI (yet), or distinguish between MMC and DataFlash
+ * MMC stack can't (yet?) distinguish between MMC and DataFlash
* protocols during enumeration.
*/
-#define CONFIG_DATAFLASH_WRITE_VERIFY
-
/* reads can bypass the buffers */
#define OP_READ_CONTINUOUS 0xE8
#define OP_READ_PAGE 0xD2
@@ -80,7 +78,8 @@
*/
#define OP_READ_ID 0x9F
#define OP_READ_SECURITY 0x77
-#define OP_WRITE_SECURITY 0x9A /* OTP bits */
+#define OP_WRITE_SECURITY_REVC 0x9A
+#define OP_WRITE_SECURITY 0x9B /* revision D */
struct dataflash {
@@ -402,7 +401,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
(void) dataflash_waitready(priv->spi);
-#ifdef CONFIG_DATAFLASH_WRITE_VERIFY
+#ifdef CONFIG_MTD_DATAFLASH_VERIFY_WRITE
/* (3) Compare to Buffer1 */
addr = pageaddr << priv->page_offset;
@@ -431,7 +430,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
} else
status = 0;
-#endif /* CONFIG_DATAFLASH_WRITE_VERIFY */
+#endif /* CONFIG_MTD_DATAFLASH_VERIFY_WRITE */
remaining = remaining - writelen;
pageaddr++;
@@ -451,16 +450,192 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
/* ......................................................................... */
+#ifdef CONFIG_MTD_DATAFLASH_OTP
+
+static int dataflash_get_otp_info(struct mtd_info *mtd,
+ struct otp_info *info, size_t len)
+{
+ /* Report both blocks as identical: bytes 0..64, locked.
+ * Unless the user block changed from all-ones, we can't
+ * tell whether it's still writable; so we assume it isn't.
+ */
+ info->start = 0;
+ info->length = 64;
+ info->locked = 1;
+ return sizeof(*info);
+}
+
+static ssize_t otp_read(struct spi_device *spi, unsigned base,
+ uint8_t *buf, loff_t off, size_t len)
+{
+ struct spi_message m;
+ size_t l;
+ uint8_t *scratch;
+ struct spi_transfer t;
+ int status;
+
+ if (off > 64)
+ return -EINVAL;
+
+ if ((off + len) > 64)
+ len = 64 - off;
+ if (len == 0)
+ return len;
+
+ spi_message_init(&m);
+
+ l = 4 + base + off + len;
+ scratch = kzalloc(l, GFP_KERNEL);
+ if (!scratch)
+ return -ENOMEM;
+
+ /* OUT: OP_READ_SECURITY, 3 don't-care bytes, zeroes
+ * IN: ignore 4 bytes, data bytes 0..N (max 127)
+ */
+ scratch[0] = OP_READ_SECURITY;
+
+ memset(&t, 0, sizeof t);
+ t.tx_buf = scratch;
+ t.rx_buf = scratch;
+ t.len = l;
+ spi_message_add_tail(&t, &m);
+
+ dataflash_waitready(spi);
+
+ status = spi_sync(spi, &m);
+ if (status >= 0) {
+ memcpy(buf, scratch + 4 + base + off, len);
+ status = len;
+ }
+
+ kfree(scratch);
+ return status;
+}
+
+static int dataflash_read_fact_otp(struct mtd_info *mtd,
+ loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ struct dataflash *priv = (struct dataflash *)mtd->priv;
+ int status;
+
+ /* 64 bytes, from 0..63 ... start at 64 on-chip */
+ mutex_lock(&priv->lock);
+ status = otp_read(priv->spi, 64, buf, from, len);
+ mutex_unlock(&priv->lock);
+
+ if (status < 0)
+ return status;
+ *retlen = status;
+ return 0;
+}
+
+static int dataflash_read_user_otp(struct mtd_info *mtd,
+ loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ struct dataflash *priv = (struct dataflash *)mtd->priv;
+ int status;
+
+ /* 64 bytes, from 0..63 ... start at 0 on-chip */
+ mutex_lock(&priv->lock);
+ status = otp_read(priv->spi, 0, buf, from, len);
+ mutex_unlock(&priv->lock);
+
+ if (status < 0)
+ return status;
+ *retlen = status;
+ return 0;
+}
+
+static int dataflash_write_user_otp(struct mtd_info *mtd,
+ loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ struct spi_message m;
+ const size_t l = 4 + 64;
+ uint8_t *scratch;
+ struct spi_transfer t;
+ struct dataflash *priv = (struct dataflash *)mtd->priv;
+ int status;
+
+ if (len > 64)
+ return -EINVAL;
+
+ /* Strictly speaking, we *could* truncate the write ... but
+ * let's not do that for the only write that's ever possible.
+ */
+ if ((from + len) > 64)
+ return -EINVAL;
+
+ /* OUT: OP_WRITE_SECURITY, 3 zeroes, 64 data-or-zero bytes
+ * IN: ignore all
+ */
+ scratch = kzalloc(l, GFP_KERNEL);
+ if (!scratch)
+ return -ENOMEM;
+ scratch[0] = OP_WRITE_SECURITY;
+ memcpy(scratch + 4 + from, buf, len);
+
+ spi_message_init(&m);
+
+ memset(&t, 0, sizeof t);
+ t.tx_buf = scratch;
+ t.len = l;
+ spi_message_add_tail(&t, &m);
+
+ /* Write the OTP bits, if they've not yet been written.
+ * This modifies SRAM buffer1.
+ */
+ mutex_lock(&priv->lock);
+ dataflash_waitready(priv->spi);
+ status = spi_sync(priv->spi, &m);
+ mutex_unlock(&priv->lock);
+
+ kfree(scratch);
+
+ if (status >= 0) {
+ status = 0;
+ *retlen = len;
+ }
+ return status;
+}
+
+static char *otp_setup(struct mtd_info *device, char revision)
+{
+ device->get_fact_prot_info = dataflash_get_otp_info;
+ device->read_fact_prot_reg = dataflash_read_fact_otp;
+ device->get_user_prot_info = dataflash_get_otp_info;
+ device->read_user_prot_reg = dataflash_read_user_otp;
+
+ /* rev c parts (at45db321c and at45db1281 only!) use a
+ * different write procedure; not (yet?) implemented.
+ */
+ if (revision > 'c')
+ device->write_user_prot_reg = dataflash_write_user_otp;
+
+ return ", OTP";
+}
+
+#else
+
+static char *otp_setup(struct mtd_info *device, char revision)
+{
+ return " (OTP)";
+}
+
+#endif
+
+/* ......................................................................... */
+
/*
* Register DataFlash device with MTD subsystem.
*/
static int __devinit
-add_dataflash(struct spi_device *spi, char *name,
- int nr_pages, int pagesize, int pageoffset)
+add_dataflash_otp(struct spi_device *spi, char *name,
+ int nr_pages, int pagesize, int pageoffset, char revision)
{
struct dataflash *priv;
struct mtd_info *device;
struct flash_platform_data *pdata = spi->dev.platform_data;
+ char *otp_tag = "";
priv = kzalloc(sizeof *priv, GFP_KERNEL);
if (!priv)
@@ -489,8 +664,12 @@ add_dataflash(struct spi_device *spi, char *name,
device->write = dataflash_write;
device->priv = priv;
- dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes\n",
- name, DIV_ROUND_UP(device->size, 1024), pagesize);
+ 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),
+ pagesize, otp_tag);
dev_set_drvdata(&spi->dev, priv);
if (mtd_has_partitions()) {
@@ -519,6 +698,14 @@ add_dataflash(struct spi_device *spi, char *name,
return add_mtd_device(device) == 1 ? -ENODEV : 0;
}
+static inline int __devinit
+add_dataflash(struct spi_device *spi, char *name,
+ int nr_pages, int pagesize, int pageoffset)
+{
+ return add_dataflash_otp(spi, name, nr_pages, pagesize,
+ pageoffset, 0);
+}
+
struct flash_info {
char *name;
@@ -664,13 +851,16 @@ static int __devinit dataflash_probe(struct spi_device *spi)
* Try to detect dataflash by JEDEC ID.
* If it succeeds we know we have either a C or D part.
* D will support power of 2 pagesize option.
+ * Both support the security register, though with different
+ * write procedures.
*/
info = jedec_probe(spi);
if (IS_ERR(info))
return PTR_ERR(info);
if (info != NULL)
- return add_dataflash(spi, info->name, info->nr_pages,
- info->pagesize, info->pageoffset);
+ return add_dataflash_otp(spi, info->name, info->nr_pages,
+ info->pagesize, info->pageoffset,
+ (info->flags & SUP_POW2PS) ? 'd' : 'c');
/*
* Older chips support only legacy commands, identifing
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index c4f9d3378b2..50ce13887f6 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -388,6 +388,10 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
if (thisEUN == targetEUN)
break;
+ /* Unlink the last block from the chain. */
+ inftl->PUtable[prevEUN] = BLOCK_NIL;
+
+ /* Now try to erase it. */
if (INFTL_formatblock(inftl, thisEUN) < 0) {
/*
* Could not erase : mark block as reserved.
@@ -396,7 +400,6 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
} else {
/* Correctly erased : mark it as free */
inftl->PUtable[thisEUN] = BLOCK_FREE;
- inftl->PUtable[prevEUN] = BLOCK_NIL;
inftl->numfreeEUNs++;
}
}
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index df8e00bba07..5ea16936216 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -332,30 +332,6 @@ config MTD_CFI_FLAGADM
Mapping for the Flaga digital module. If you don't have one, ignore
this setting.
-config MTD_WALNUT
- tristate "Flash device mapped on IBM 405GP Walnut"
- depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE
- help
- This enables access routines for the flash chips on the IBM 405GP
- Walnut board. If you have one of these boards and would like to
- use the flash chips on it, say 'Y'.
-
-config MTD_EBONY
- tristate "Flash devices mapped on IBM 440GP Ebony"
- depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE
- help
- This enables access routines for the flash chips on the IBM 440GP
- Ebony board. If you have one of these boards and would like to
- use the flash chips on it, say 'Y'.
-
-config MTD_OCOTEA
- tristate "Flash devices mapped on IBM 440GX Ocotea"
- depends on MTD_CFI && OCOTEA && !PPC_MERGE
- help
- This enables access routines for the flash chips on the IBM 440GX
- Ocotea board. If you have one of these boards and would like to
- use the flash chips on it, say 'Y'.
-
config MTD_REDWOOD
tristate "CFI Flash devices mapped on IBM Redwood"
depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 )
@@ -458,13 +434,6 @@ config MTD_CEIVA
PhotoMax Digital Picture Frame.
If you have such a device, say 'Y'.
-config MTD_NOR_TOTO
- tristate "NOR Flash device on TOTO board"
- depends on ARCH_OMAP && OMAP_TOTO
- help
- This enables access to the NOR flash on the Texas Instruments
- TOTO board.
-
config MTD_H720X
tristate "Hynix evaluation board mappings"
depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 )
@@ -522,7 +491,7 @@ config MTD_BFIN_ASYNC
config MTD_UCLINUX
tristate "Generic uClinux RAM/ROM filesystem support"
- depends on MTD_PARTITIONS && !MMU
+ depends on MTD_PARTITIONS && MTD_RAM && !MMU
help
Map driver to support image based filesystems for uClinux.
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 6cda6df973e..6d9ba35caf1 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -50,12 +50,8 @@ obj-$(CONFIG_MTD_REDWOOD) += redwood.o
obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
obj-$(CONFIG_MTD_NETtel) += nettel.o
obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
-obj-$(CONFIG_MTD_EBONY) += ebony.o
-obj-$(CONFIG_MTD_OCOTEA) += ocotea.o
-obj-$(CONFIG_MTD_WALNUT) += walnut.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
-obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o
obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c
deleted file mode 100644
index d92b7c70d3e..00000000000
--- a/drivers/mtd/maps/ebony.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Mapping for Ebony user flash
- *
- * Matt Porter <mporter@kernel.crashing.org>
- *
- * Copyright 2002-2004 MontaVista Software 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.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <asm/io.h>
-#include <asm/ibm44x.h>
-#include <platforms/4xx/ebony.h>
-
-static struct mtd_info *flash;
-
-static struct map_info ebony_small_map = {
- .name = "Ebony small flash",
- .size = EBONY_SMALL_FLASH_SIZE,
- .bankwidth = 1,
-};
-
-static struct map_info ebony_large_map = {
- .name = "Ebony large flash",
- .size = EBONY_LARGE_FLASH_SIZE,
- .bankwidth = 1,
-};
-
-static struct mtd_partition ebony_small_partitions[] = {
- {
- .name = "OpenBIOS",
- .offset = 0x0,
- .size = 0x80000,
- }
-};
-
-static struct mtd_partition ebony_large_partitions[] = {
- {
- .name = "fs",
- .offset = 0,
- .size = 0x380000,
- },
- {
- .name = "firmware",
- .offset = 0x380000,
- .size = 0x80000,
- }
-};
-
-int __init init_ebony(void)
-{
- u8 fpga0_reg;
- u8 __iomem *fpga0_adr;
- unsigned long long small_flash_base, large_flash_base;
-
- fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16);
- if (!fpga0_adr)
- return -ENOMEM;
-
- fpga0_reg = readb(fpga0_adr);
- iounmap(fpga0_adr);
-
- if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
- !EBONY_FLASH_SEL(fpga0_reg))
- small_flash_base = EBONY_SMALL_FLASH_HIGH2;
- else if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
- EBONY_FLASH_SEL(fpga0_reg))
- small_flash_base = EBONY_SMALL_FLASH_HIGH1;
- else if (!EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
- !EBONY_FLASH_SEL(fpga0_reg))
- small_flash_base = EBONY_SMALL_FLASH_LOW2;
- else
- small_flash_base = EBONY_SMALL_FLASH_LOW1;
-
- if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
- !EBONY_ONBRD_FLASH_EN(fpga0_reg))
- large_flash_base = EBONY_LARGE_FLASH_LOW;
- else
- large_flash_base = EBONY_LARGE_FLASH_HIGH;
-
- ebony_small_map.phys = small_flash_base;
- ebony_small_map.virt = ioremap64(small_flash_base,
- ebony_small_map.size);
-
- if (!ebony_small_map.virt) {
- printk("Failed to ioremap flash\n");
- return -EIO;
- }
-
- simple_map_init(&ebony_small_map);
-
- flash = do_map_probe("jedec_probe", &ebony_small_map);
- if (flash) {
- flash->owner = THIS_MODULE;
- add_mtd_partitions(flash, ebony_small_partitions,
- ARRAY_SIZE(ebony_small_partitions));
- } else {
- printk("map probe failed for flash\n");
- iounmap(ebony_small_map.virt);
- return -ENXIO;
- }
-
- ebony_large_map.phys = large_flash_base;
- ebony_large_map.virt = ioremap64(large_flash_base,
- ebony_large_map.size);
-
- if (!ebony_large_map.virt) {
- printk("Failed to ioremap flash\n");
- iounmap(ebony_small_map.virt);
- return -EIO;
- }
-
- simple_map_init(&ebony_large_map);
-
- flash = do_map_probe("jedec_probe", &ebony_large_map);
- if (flash) {
- flash->owner = THIS_MODULE;
- add_mtd_partitions(flash, ebony_large_partitions,
- ARRAY_SIZE(ebony_large_partitions));
- } else {
- printk("map probe failed for flash\n");
- iounmap(ebony_small_map.virt);
- iounmap(ebony_large_map.virt);
- return -ENXIO;
- }
-
- return 0;
-}
-
-static void __exit cleanup_ebony(void)
-{
- if (flash) {
- del_mtd_partitions(flash);
- map_destroy(flash);
- }
-
- if (ebony_small_map.virt) {
- iounmap(ebony_small_map.virt);
- ebony_small_map.virt = NULL;
- }
-
- if (ebony_large_map.virt) {
- iounmap(ebony_large_map.virt);
- ebony_large_map.virt = NULL;
- }
-}
-
-module_init(init_ebony);
-module_exit(cleanup_ebony);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards");
diff --git a/drivers/mtd/maps/ocotea.c b/drivers/mtd/maps/ocotea.c
deleted file mode 100644
index 5522eac8c98..00000000000
--- a/drivers/mtd/maps/ocotea.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Mapping for Ocotea user flash
- *
- * Matt Porter <mporter@kernel.crashing.org>
- *
- * Copyright 2002-2004 MontaVista Software 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.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <asm/io.h>
-#include <asm/ibm44x.h>
-#include <platforms/4xx/ocotea.h>
-
-static struct mtd_info *flash;
-
-static struct map_info ocotea_small_map = {
- .name = "Ocotea small flash",
- .size = OCOTEA_SMALL_FLASH_SIZE,
- .buswidth = 1,
-};
-
-static struct map_info ocotea_large_map = {
- .name = "Ocotea large flash",
- .size = OCOTEA_LARGE_FLASH_SIZE,
- .buswidth = 1,
-};
-
-static struct mtd_partition ocotea_small_partitions[] = {
- {
- .name = "pibs",
- .offset = 0x0,
- .size = 0x100000,
- }
-};
-
-static struct mtd_partition ocotea_large_partitions[] = {
- {
- .name = "fs",
- .offset = 0,
- .size = 0x300000,
- },
- {
- .name = "firmware",
- .offset = 0x300000,
- .size = 0x100000,
- }
-};
-
-int __init init_ocotea(void)
-{
- u8 fpga0_reg;
- u8 *fpga0_adr;
- unsigned long long small_flash_base, large_flash_base;
-
- fpga0_adr = ioremap64(OCOTEA_FPGA_ADDR, 16);
- if (!fpga0_adr)
- return -ENOMEM;
-
- fpga0_reg = readb((unsigned long)fpga0_adr);
- iounmap(fpga0_adr);
-
- if (OCOTEA_BOOT_LARGE_FLASH(fpga0_reg)) {
- small_flash_base = OCOTEA_SMALL_FLASH_HIGH;
- large_flash_base = OCOTEA_LARGE_FLASH_LOW;
- }
- else {
- small_flash_base = OCOTEA_SMALL_FLASH_LOW;
- large_flash_base = OCOTEA_LARGE_FLASH_HIGH;
- }
-
- ocotea_small_map.phys = small_flash_base;
- ocotea_small_map.virt = ioremap64(small_flash_base,
- ocotea_small_map.size);
-
- if (!ocotea_small_map.virt) {
- printk("Failed to ioremap flash\n");
- return -EIO;
- }
-
- simple_map_init(&ocotea_small_map);
-
- flash = do_map_probe("map_rom", &ocotea_small_map);
- if (flash) {
- flash->owner = THIS_MODULE;
- add_mtd_partitions(flash, ocotea_small_partitions,
- ARRAY_SIZE(ocotea_small_partitions));
- } else {
- printk("map probe failed for flash\n");
- iounmap(ocotea_small_map.virt);
- return -ENXIO;
- }
-
- ocotea_large_map.phys = large_flash_base;
- ocotea_large_map.virt = ioremap64(large_flash_base,
- ocotea_large_map.size);
-
- if (!ocotea_large_map.virt) {
- printk("Failed to ioremap flash\n");
- iounmap(ocotea_small_map.virt);
- return -EIO;
- }
-
- simple_map_init(&ocotea_large_map);
-
- flash = do_map_probe("cfi_probe", &ocotea_large_map);
- if (flash) {
- flash->owner = THIS_MODULE;
- add_mtd_partitions(flash, ocotea_large_partitions,
- ARRAY_SIZE(ocotea_large_partitions));
- } else {
- printk("map probe failed for flash\n");
- iounmap(ocotea_small_map.virt);
- iounmap(ocotea_large_map.virt);
- return -ENXIO;
- }
-
- return 0;
-}
-
-static void __exit cleanup_ocotea(void)
-{
- if (flash) {
- del_mtd_partitions(flash);
- map_destroy(flash);
- }
-
- if (ocotea_small_map.virt) {
- iounmap((void *)ocotea_small_map.virt);
- ocotea_small_map.virt = 0;
- }
-
- if (ocotea_large_map.virt) {
- iounmap((void *)ocotea_large_map.virt);
- ocotea_large_map.virt = 0;
- }
-}
-
-module_init(init_ocotea);
-module_exit(cleanup_ocotea);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 440GX Ocotea boards");
diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c
deleted file mode 100644
index 0a60ebbc217..00000000000
--- a/drivers/mtd/maps/omap-toto-flash.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * NOR Flash memory access on TI Toto board
- *
- * jzhang@ti.com (C) 2003 Texas Instruments.
- *
- * (C) 2002 MontVista Software, Inc.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/hardware.h>
-#include <asm/io.h>
-
-
-#ifndef CONFIG_ARCH_OMAP
-#error This is for OMAP architecture only
-#endif
-
-//these lines need be moved to a hardware header file
-#define OMAP_TOTO_FLASH_BASE 0xd8000000
-#define OMAP_TOTO_FLASH_SIZE 0x80000
-
-static struct map_info omap_toto_map_flash = {
- .name = "OMAP Toto flash",
- .bankwidth = 2,
- .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE,
-};
-
-
-static struct mtd_partition toto_flash_partitions[] = {
- {
- .name = "BootLoader",
- .size = 0x00040000, /* hopefully u-boot will stay 128k + 128*/
- .offset = 0,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "ReservedSpace",
- .size = 0x00030000,
- .offset = MTDPART_OFS_APPEND,
- //mask_flags: MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "EnvArea", /* bottom 64KiB for env vars */
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- }
-};
-
-static struct mtd_partition *parsed_parts;
-
-static struct mtd_info *flash_mtd;
-
-static int __init init_flash (void)
-{
-
- struct mtd_partition *parts;
- int nb_parts = 0;
- int parsed_nr_parts = 0;
- const char *part_type;
-
- /*
- * Static partition definition selection
- */
- part_type = "static";
-
- parts = toto_flash_partitions;
- nb_parts = ARRAY_SIZE(toto_flash_partitions);
- omap_toto_map_flash.size = OMAP_TOTO_FLASH_SIZE;
- omap_toto_map_flash.phys = virt_to_phys(OMAP_TOTO_FLASH_BASE);
-
- simple_map_init(&omap_toto_map_flash);
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "OMAP toto flash: probing %d-bit flash bus\n",
- omap_toto_map_flash.bankwidth*8);
- flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash);
- if (!flash_mtd)
- return -ENXIO;
-
- if (parsed_nr_parts > 0) {
- parts = parsed_parts;
- nb_parts = parsed_nr_parts;
- }
-
- if (nb_parts == 0) {
- printk(KERN_NOTICE "OMAP toto flash: no partition info available,"
- "registering whole flash at once\n");
- if (add_mtd_device(flash_mtd)){
- return -ENXIO;
- }
- } else {
- printk(KERN_NOTICE "Using %s partition definition\n",
- part_type);
- return add_mtd_partitions(flash_mtd, parts, nb_parts);
- }
- return 0;
-}
-
-int __init omap_toto_mtd_init(void)
-{
- int status;
-
- if (status = init_flash()) {
- printk(KERN_ERR "OMAP Toto Flash: unable to init map for toto flash\n");
- }
- return status;
-}
-
-static void __exit omap_toto_mtd_cleanup(void)
-{
- if (flash_mtd) {
- del_mtd_partitions(flash_mtd);
- map_destroy(flash_mtd);
- kfree(parsed_parts);
- }
-}
-
-module_init(omap_toto_mtd_init);
-module_exit(omap_toto_mtd_cleanup);
-
-MODULE_AUTHOR("Jian Zhang");
-MODULE_DESCRIPTION("OMAP Toto board map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
index 5c6a25c9038..48f4cf5cb9d 100644
--- a/drivers/mtd/maps/pci.c
+++ b/drivers/mtd/maps/pci.c
@@ -203,15 +203,8 @@ intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map)
* not enabled, should we be allocating a new resource for it
* or simply enabling it?
*/
- if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) &
- IORESOURCE_ROM_ENABLE)) {
- u32 val;
- pci_resource_flags(dev, PCI_ROM_RESOURCE) |= IORESOURCE_ROM_ENABLE;
- pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
- val |= PCI_ROM_ADDRESS_ENABLE;
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
- printk("%s: enabling expansion ROM\n", pci_name(dev));
- }
+ pci_enable_rom(dev);
+ printk("%s: enabling expansion ROM\n", pci_name(dev));
}
if (!len || !base)
@@ -232,18 +225,13 @@ intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map)
static void
intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map)
{
- u32 val;
-
if (map->base)
iounmap(map->base);
/*
* We need to undo the PCI BAR2/PCI ROM BAR address alteration.
*/
- pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~IORESOURCE_ROM_ENABLE;
- pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
- val &= ~PCI_ROM_ADDRESS_ENABLE;
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
+ pci_disable_rom(dev);
}
static unsigned long
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 49acd417189..5fcfec034a9 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -230,8 +230,7 @@ static int __devinit of_flash_probe(struct of_device *dev,
#ifdef CONFIG_MTD_OF_PARTS
if (err == 0) {
- err = of_mtd_parse_partitions(&dev->dev, info->mtd,
- dp, &info->parts);
+ err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
if (err < 0)
return err;
}
diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c
deleted file mode 100644
index e243476c817..00000000000
--- a/drivers/mtd/maps/walnut.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Mapping for Walnut flash
- * (used ebony.c as a "framework")
- *
- * Heikki Lindholm <holindho@infradead.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/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <asm/io.h>
-#include <asm/ibm4xx.h>
-#include <platforms/4xx/walnut.h>
-
-/* these should be in platforms/4xx/walnut.h ? */
-#define WALNUT_FLASH_ONBD_N(x) (x & 0x02)
-#define WALNUT_FLASH_SRAM_SEL(x) (x & 0x01)
-#define WALNUT_FLASH_LOW 0xFFF00000
-#define WALNUT_FLASH_HIGH 0xFFF80000
-#define WALNUT_FLASH_SIZE 0x80000
-
-static struct mtd_info *flash;
-
-static struct map_info walnut_map = {
- .name = "Walnut flash",
- .size = WALNUT_FLASH_SIZE,
- .bankwidth = 1,
-};
-
-/* Actually, OpenBIOS is the last 128 KiB of the flash - better
- * partitioning could be made */
-static struct mtd_partition walnut_partitions[] = {
- {
- .name = "OpenBIOS",
- .offset = 0x0,
- .size = WALNUT_FLASH_SIZE,
- /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */
- }
-};
-
-int __init init_walnut(void)
-{
- u8 fpga_brds1;
- void *fpga_brds1_adr;
- void *fpga_status_adr;
- unsigned long flash_base;
-
- /* this should already be mapped (platform/4xx/walnut.c) */
- fpga_status_adr = ioremap(WALNUT_FPGA_BASE, 8);
- if (!fpga_status_adr)
- return -ENOMEM;
-
- fpga_brds1_adr = fpga_status_adr+5;
- fpga_brds1 = readb(fpga_brds1_adr);
- /* iounmap(fpga_status_adr); */
-
- if (WALNUT_FLASH_ONBD_N(fpga_brds1)) {
- printk("The on-board flash is disabled (U79 sw 5)!");
- iounmap(fpga_status_adr);
- return -EIO;
- }
- if (WALNUT_FLASH_SRAM_SEL(fpga_brds1))
- flash_base = WALNUT_FLASH_LOW;
- else
- flash_base = WALNUT_FLASH_HIGH;
-
- walnut_map.phys = flash_base;
- walnut_map.virt =
- (void __iomem *)ioremap(flash_base, walnut_map.size);
-
- if (!walnut_map.virt) {
- printk("Failed to ioremap flash.\n");
- iounmap(fpga_status_adr);
- return -EIO;
- }
-
- simple_map_init(&walnut_map);
-
- flash = do_map_probe("jedec_probe", &walnut_map);
- if (flash) {
- flash->owner = THIS_MODULE;
- add_mtd_partitions(flash, walnut_partitions,
- ARRAY_SIZE(walnut_partitions));
- } else {
- printk("map probe failed for flash\n");
- iounmap(fpga_status_adr);
- return -ENXIO;
- }
-
- iounmap(fpga_status_adr);
- return 0;
-}
-
-static void __exit cleanup_walnut(void)
-{
- if (flash) {
- del_mtd_partitions(flash);
- map_destroy(flash);
- }
-
- if (walnut_map.virt) {
- iounmap((void *)walnut_map.virt);
- walnut_map.virt = 0;
- }
-}
-
-module_init(init_walnut);
-module_exit(cleanup_walnut);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Heikki Lindholm <holindho@infradead.org>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 405GP Walnut boards");
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 681d5aca2af..1409f01406f 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -133,15 +133,12 @@ static void mtd_blktrans_request(struct request_queue *rq)
}
-static int blktrans_open(struct inode *i, struct file *f)
+static int blktrans_open(struct block_device *bdev, fmode_t mode)
{
- struct mtd_blktrans_dev *dev;
- struct mtd_blktrans_ops *tr;
+ struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data;
+ struct mtd_blktrans_ops *tr = dev->tr;
int ret = -ENODEV;
- dev = i->i_bdev->bd_disk->private_data;
- tr = dev->tr;
-
if (!try_module_get(dev->mtd->owner))
goto out;
@@ -164,15 +161,12 @@ static int blktrans_open(struct inode *i, struct file *f)
return ret;
}
-static int blktrans_release(struct inode *i, struct file *f)
+static int blktrans_release(struct gendisk *disk, fmode_t mode)
{
- struct mtd_blktrans_dev *dev;
- struct mtd_blktrans_ops *tr;
+ struct mtd_blktrans_dev *dev = disk->private_data;
+ struct mtd_blktrans_ops *tr = dev->tr;
int ret = 0;
- dev = i->i_bdev->bd_disk->private_data;
- tr = dev->tr;
-
if (tr->release)
ret = tr->release(dev);
@@ -194,10 +188,10 @@ static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return -ENOTTY;
}
-static int blktrans_ioctl(struct inode *inode, struct file *file,
+static int blktrans_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data;
+ struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data;
struct mtd_blktrans_ops *tr = dev->tr;
switch (cmd) {
@@ -215,7 +209,7 @@ static struct block_device_operations mtd_blktrans_ops = {
.owner = THIS_MODULE,
.open = blktrans_open,
.release = blktrans_release,
- .ioctl = blktrans_ioctl,
+ .locked_ioctl = blktrans_ioctl,
.getgeo = blktrans_getgeo,
};
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 1c74762dec8..bcffeda2df3 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -96,7 +96,7 @@ static int mtd_open(struct inode *inode, struct file *file)
return -ENODEV;
/* You can't open the RO devices RW */
- if ((file->f_mode & 2) && (minor & 1))
+ if ((file->f_mode & FMODE_WRITE) && (minor & 1))
return -EACCES;
lock_kernel();
@@ -114,7 +114,7 @@ static int mtd_open(struct inode *inode, struct file *file)
}
/* You can't open it RW if it's not a writeable device */
- if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) {
+ if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
put_mtd_device(mtd);
ret = -EACCES;
goto out;
@@ -144,7 +144,7 @@ static int mtd_close(struct inode *inode, struct file *file)
DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
/* Only sync if opened RW */
- if ((file->f_mode & 2) && mtd->sync)
+ if ((file->f_mode & FMODE_WRITE) && mtd->sync)
mtd->sync(mtd);
put_mtd_device(mtd);
@@ -348,7 +348,7 @@ static void mtdchar_erase_callback (struct erase_info *instr)
wake_up((wait_queue_head_t *)instr->priv);
}
-#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP)
+#ifdef CONFIG_HAVE_MTD_OTP
static int otp_select_filemode(struct mtd_file_info *mfi, int mode)
{
struct mtd_info *mtd = mfi->mtd;
@@ -443,7 +443,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
{
struct erase_info *erase;
- if(!(file->f_mode & 2))
+ if(!(file->f_mode & FMODE_WRITE))
return -EPERM;
erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL);
@@ -497,7 +497,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
struct mtd_oob_buf __user *user_buf = argp;
uint32_t retlen;
- if(!(file->f_mode & 2))
+ if(!(file->f_mode & FMODE_WRITE))
return -EPERM;
if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
@@ -665,7 +665,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
break;
}
-#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP)
+#ifdef CONFIG_HAVE_MTD_OTP
case OTPSELECT:
{
int mode;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 2972a5edb73..789842d0e6f 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -444,7 +444,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
return -EINVAL;
}
- instr->fail_addr = 0xffffffff;
+ instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
/* make a local copy of instr to avoid modifying the caller's struct */
erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
@@ -493,7 +493,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
/* sanity check: should never happen since
* block alignment has been checked above */
BUG_ON(err == -EINVAL);
- if (erase->fail_addr != 0xffffffff)
+ if (erase->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr = erase->fail_addr + offset;
break;
}
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 5a680e1e61f..aebb3b27edb 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -33,6 +33,7 @@
#include <linux/interrupt.h>
#include <linux/mtd/mtd.h>
+#define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
#define OOPS_PAGE_SIZE 4096
static struct mtdoops_context {
@@ -99,7 +100,7 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
int ret;
cxt->nextpage++;
- if (cxt->nextpage > cxt->oops_pages)
+ if (cxt->nextpage >= cxt->oops_pages)
cxt->nextpage = 0;
cxt->nextcount++;
if (cxt->nextcount == 0xffffffff)
@@ -141,7 +142,7 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
mod = (cxt->nextpage * OOPS_PAGE_SIZE) % mtd->erasesize;
if (mod != 0) {
cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / OOPS_PAGE_SIZE);
- if (cxt->nextpage > cxt->oops_pages)
+ if (cxt->nextpage >= cxt->oops_pages)
cxt->nextpage = 0;
}
@@ -158,7 +159,7 @@ badblock:
cxt->nextpage * OOPS_PAGE_SIZE);
i++;
cxt->nextpage = cxt->nextpage + (mtd->erasesize / OOPS_PAGE_SIZE);
- if (cxt->nextpage > cxt->oops_pages)
+ if (cxt->nextpage >= cxt->oops_pages)
cxt->nextpage = 0;
if (i == (cxt->oops_pages / (mtd->erasesize / OOPS_PAGE_SIZE))) {
printk(KERN_ERR "mtdoops: All blocks bad!\n");
@@ -224,40 +225,40 @@ static void find_next_position(struct mtdoops_context *cxt)
{
struct mtd_info *mtd = cxt->mtd;
int ret, page, maxpos = 0;
- u32 count, maxcount = 0xffffffff;
+ u32 count[2], maxcount = 0xffffffff;
size_t retlen;
for (page = 0; page < cxt->oops_pages; page++) {
- ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
- if ((retlen != 4) || ((ret < 0) && (ret != -EUCLEAN))) {
- printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
+ ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 8, &retlen, (u_char *) &count[0]);
+ if ((retlen != 8) || ((ret < 0) && (ret != -EUCLEAN))) {
+ printk(KERN_ERR "mtdoops: Read failure at %d (%td of 8 read)"
", err %d.\n", page * OOPS_PAGE_SIZE, retlen, ret);
continue;
}
- if (count == 0xffffffff)
+ if (count[1] != MTDOOPS_KERNMSG_MAGIC)
+ continue;
+ if (count[0] == 0xffffffff)
continue;
if (maxcount == 0xffffffff) {
- maxcount = count;
+ maxcount = count[0];
maxpos = page;
- } else if ((count < 0x40000000) && (maxcount > 0xc0000000)) {
- maxcount = count;
+ } else if ((count[0] < 0x40000000) && (maxcount > 0xc0000000)) {
+ maxcount = count[0];
maxpos = page;
- } else if ((count > maxcount) && (count < 0xc0000000)) {
- maxcount = count;
+ } else if ((count[0] > maxcount) && (count[0] < 0xc0000000)) {
+ maxcount = count[0];
maxpos = page;
- } else if ((count > maxcount) && (count > 0xc0000000)
+ } else if ((count[0] > maxcount) && (count[0] > 0xc0000000)
&& (maxcount > 0x80000000)) {
- maxcount = count;
+ maxcount = count[0];
maxpos = page;
}
}
if (maxcount == 0xffffffff) {
cxt->nextpage = 0;
cxt->nextcount = 1;
- cxt->ready = 1;
- printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n",
- cxt->nextpage, cxt->nextcount);
+ schedule_work(&cxt->work_erase);
return;
}
@@ -358,8 +359,9 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
if (cxt->writecount == 0) {
u32 *stamp = cxt->oops_buf;
- *stamp = cxt->nextcount;
- cxt->writecount = 4;
+ *stamp++ = cxt->nextcount;
+ *stamp = MTDOOPS_KERNMSG_MAGIC;
+ cxt->writecount = 8;
}
if ((count + cxt->writecount) > OOPS_PAGE_SIZE)
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 9a06dc93ee0..3728913fa5f 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -214,7 +214,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
instr->addr += part->offset;
ret = part->master->erase(part->master, instr);
if (ret) {
- if (instr->fail_addr != 0xffffffff)
+ if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr -= part->offset;
instr->addr -= part->offset;
}
@@ -226,7 +226,7 @@ void mtd_erase_callback(struct erase_info *instr)
if (instr->mtd->erase == part_erase) {
struct mtd_part *part = PART(instr->mtd);
- if (instr->fail_addr != 0xffffffff)
+ if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr -= part->offset;
instr->addr -= part->offset;
}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 41f361c49b3..1c2e9450d66 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -56,6 +56,12 @@ config MTD_NAND_H1900
help
This enables the driver for the iPAQ h1900 flash.
+config MTD_NAND_GPIO
+ tristate "GPIO NAND Flash driver"
+ depends on GENERIC_GPIO && ARM
+ help
+ This enables a GPIO based NAND flash driver.
+
config MTD_NAND_SPIA
tristate "NAND Flash device on SPIA board"
depends on ARCH_P720T
@@ -68,12 +74,6 @@ config MTD_NAND_AMS_DELTA
help
Support for NAND flash on Amstrad E3 (Delta).
-config MTD_NAND_TOTO
- tristate "NAND Flash device on TOTO board"
- depends on ARCH_OMAP && BROKEN
- help
- Support for NAND flash on Texas Instruments Toto platform.
-
config MTD_NAND_TS7250
tristate "NAND Flash device on TS-7250 board"
depends on MACH_TS72XX
@@ -163,13 +163,6 @@ 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 && !PPC_MERGE
- 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
@@ -340,6 +333,13 @@ config MTD_NAND_PXA3xx
This enables the driver for the NAND flash device found on
PXA3xx processors
+config MTD_NAND_PXA3xx_BUILTIN
+ bool "Use builtin definitions for some NAND chips (deprecated)"
+ depends on MTD_NAND_PXA3xx
+ help
+ This enables builtin definitions for some NAND chips. This
+ is deprecated in favor of platform specific data.
+
config MTD_NAND_CM_X270
tristate "Support for NAND Flash on CM-X270 modules"
depends on MTD_NAND && MACH_ARMCORE
@@ -400,10 +400,24 @@ config MTD_NAND_FSL_ELBC
config MTD_NAND_FSL_UPM
tristate "Support for NAND on Freescale UPM"
- depends on MTD_NAND && OF_GPIO && (PPC_83xx || PPC_85xx)
+ depends on MTD_NAND && (PPC_83xx || PPC_85xx)
select FSL_LBC
help
Enables support for NAND Flash chips wired onto Freescale PowerPC
processor localbus with User-Programmable Machine support.
+config MTD_NAND_MXC
+ tristate "MXC NAND support"
+ depends on ARCH_MX2
+ help
+ This enables the driver for the NAND flash controller on the
+ MXC processors.
+
+config MTD_NAND_SH_FLCTL
+ tristate "Support for NAND on Renesas SuperH FLCTL"
+ depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723
+ help
+ Several Renesas SuperH CPU has FLCTL. This option enables support
+ for NAND Flash using FLCTL. This driver support SH7723.
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index b786c5da82d..b661586afbf 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -8,7 +8,6 @@ obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
-obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
@@ -24,6 +23,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
+obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
@@ -34,5 +34,7 @@ obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
+obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
+obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c
index 257937cd99b..96238039485 100644
--- a/drivers/mtd/nand/alauda.c
+++ b/drivers/mtd/nand/alauda.c
@@ -691,7 +691,7 @@ static int alauda_probe(struct usb_interface *interface,
al[0].port = ALAUDA_PORT_XD;
al[1].port = ALAUDA_PORT_SM;
- info("alauda probed");
+ dev_info(&interface->dev, "alauda probed\n");
alauda_check_media(al);
alauda_check_media(al+1);
@@ -716,7 +716,7 @@ static void alauda_disconnect(struct usb_interface *interface)
if (al)
kref_put(&al->kref, alauda_delete);
- info("alauda gone");
+ dev_info(&interface->dev, "alauda gone");
}
static struct usb_driver alauda_driver = {
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 3387e0d5076..c98c1570a40 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -174,48 +174,6 @@ static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len)
}
/*
- * write oob for small pages
- */
-static int atmel_nand_write_oob_512(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
-{
- int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
- int eccsize = chip->ecc.size, length = mtd->oobsize;
- int len, pos, status = 0;
- const uint8_t *bufpoi = chip->oob_poi;
-
- pos = eccsize + chunk;
-
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
- len = min_t(int, length, chunk);
- chip->write_buf(mtd, bufpoi, len);
- bufpoi += len;
- length -= len;
- if (length > 0)
- chip->write_buf(mtd, bufpoi, length);
-
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
-
- return status & NAND_STATUS_FAIL ? -EIO : 0;
-
-}
-
-/*
- * read oob for small pages
- */
-static int atmel_nand_read_oob_512(struct mtd_info *mtd,
- struct nand_chip *chip, int page, int sndcmd)
-{
- if (sndcmd) {
- chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
- sndcmd = 0;
- }
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- return sndcmd;
-}
-
-/*
* Calculate HW ECC
*
* function called after a write
@@ -235,14 +193,14 @@ static int atmel_nand_calculate(struct mtd_info *mtd,
/* get the first 2 ECC bytes */
ecc_value = ecc_readl(host->ecc, PR);
- ecc_code[eccpos[0]] = ecc_value & 0xFF;
- ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF;
+ ecc_code[0] = ecc_value & 0xFF;
+ ecc_code[1] = (ecc_value >> 8) & 0xFF;
/* get the last 2 ECC bytes */
ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY;
- ecc_code[eccpos[2]] = ecc_value & 0xFF;
- ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF;
+ ecc_code[2] = ecc_value & 0xFF;
+ ecc_code[3] = (ecc_value >> 8) & 0xFF;
return 0;
}
@@ -476,14 +434,12 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
res = -EIO;
goto err_ecc_ioremap;
}
- nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+ nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.calculate = atmel_nand_calculate;
nand_chip->ecc.correct = atmel_nand_correct;
nand_chip->ecc.hwctl = atmel_nand_hwctl;
nand_chip->ecc.read_page = atmel_nand_read_page;
nand_chip->ecc.bytes = 4;
- nand_chip->ecc.prepad = 0;
- nand_chip->ecc.postpad = 0;
}
nand_chip->chip_delay = 20; /* 20us command delay time */
@@ -514,7 +470,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
goto err_scan_ident;
}
- if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) {
+ if (nand_chip->ecc.mode == NAND_ECC_HW) {
/* ECC is calculated for the whole page (1 step) */
nand_chip->ecc.size = mtd->writesize;
@@ -522,8 +478,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
switch (mtd->writesize) {
case 512:
nand_chip->ecc.layout = &atmel_oobinfo_small;
- nand_chip->ecc.read_oob = atmel_nand_read_oob_512;
- nand_chip->ecc.write_oob = atmel_nand_write_oob_512;
ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
break;
case 1024:
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index 3370a800fd3..9f1b451005c 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -289,8 +289,10 @@ static int __init cs553x_init(void)
int i;
uint64_t val;
+#ifdef CONFIG_MTD_PARTITIONS
int mtd_parts_nb = 0;
struct mtd_partition *mtd_parts = NULL;
+#endif
/* If the CPU isn't a Geode GX or LX, abort */
if (!is_geode())
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 98ad3cefcaf..4aa5bd6158d 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -918,8 +918,7 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
#ifdef CONFIG_MTD_OF_PARTS
if (ret == 0) {
- ret = of_mtd_parse_partitions(priv->dev, &priv->mtd,
- node, &parts);
+ ret = of_mtd_parse_partitions(priv->dev, node, &parts);
if (ret < 0)
goto err;
}
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
index 1ebfd87f00b..024e3fffd4b 100644
--- a/drivers/mtd/nand/fsl_upm.c
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
@@ -36,8 +37,6 @@ struct fsl_upm_nand {
uint8_t upm_cmd_offset;
void __iomem *io_base;
int rnb_gpio;
- const uint32_t *wait_pattern;
- const uint32_t *wait_write;
int chip_delay;
};
@@ -61,10 +60,11 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
if (fun->rnb_gpio >= 0) {
while (--cnt && !fun_chip_ready(&fun->mtd))
cpu_relax();
+ if (!cnt)
+ dev_err(fun->dev, "tired waiting for RNB\n");
+ } else {
+ ndelay(100);
}
-
- if (!cnt)
- dev_err(fun->dev, "tired waiting for RNB\n");
}
static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -89,8 +89,7 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
fsl_upm_run_pattern(&fun->upm, fun->io_base, cmd);
- if (fun->wait_pattern)
- fun_wait_rnb(fun);
+ fun_wait_rnb(fun);
}
static uint8_t fun_read_byte(struct mtd_info *mtd)
@@ -116,14 +115,16 @@ static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
for (i = 0; i < len; i++) {
out_8(fun->chip.IO_ADDR_W, buf[i]);
- if (fun->wait_write)
- fun_wait_rnb(fun);
+ fun_wait_rnb(fun);
}
}
-static int __devinit fun_chip_init(struct fsl_upm_nand *fun)
+static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
+ const struct device_node *upm_np,
+ const struct resource *io_res)
{
int ret;
+ struct device_node *flash_np;
#ifdef CONFIG_MTD_PARTITIONS
static const char *part_types[] = { "cmdlinepart", NULL, };
#endif
@@ -143,18 +144,37 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun)
fun->mtd.priv = &fun->chip;
fun->mtd.owner = THIS_MODULE;
+ flash_np = of_get_next_child(upm_np, NULL);
+ if (!flash_np)
+ return -ENODEV;
+
+ fun->mtd.name = kasprintf(GFP_KERNEL, "%x.%s", io_res->start,
+ flash_np->name);
+ if (!fun->mtd.name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
ret = nand_scan(&fun->mtd, 1);
if (ret)
- return ret;
-
- fun->mtd.name = fun->dev->bus_id;
+ goto err;
#ifdef CONFIG_MTD_PARTITIONS
ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0);
+
+#ifdef CONFIG_MTD_OF_PARTS
+ if (ret == 0)
+ ret = of_mtd_parse_partitions(fun->dev, &fun->mtd,
+ flash_np, &fun->parts);
+#endif
if (ret > 0)
- return add_mtd_partitions(&fun->mtd, fun->parts, ret);
+ ret = add_mtd_partitions(&fun->mtd, fun->parts, ret);
+ else
#endif
- return add_mtd_device(&fun->mtd);
+ ret = add_mtd_device(&fun->mtd);
+err:
+ of_node_put(flash_np);
+ return ret;
}
static int __devinit fun_probe(struct of_device *ofdev,
@@ -211,6 +231,12 @@ static int __devinit fun_probe(struct of_device *ofdev,
goto err2;
}
+ prop = of_get_property(ofdev->node, "chip-delay", NULL);
+ if (prop)
+ fun->chip_delay = *prop;
+ else
+ fun->chip_delay = 50;
+
fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start,
io_res.end - io_res.start + 1);
if (!fun->io_base) {
@@ -220,17 +246,8 @@ static int __devinit fun_probe(struct of_device *ofdev,
fun->dev = &ofdev->dev;
fun->last_ctrl = NAND_CLE;
- fun->wait_pattern = of_get_property(ofdev->node, "fsl,wait-pattern",
- NULL);
- fun->wait_write = of_get_property(ofdev->node, "fsl,wait-write", NULL);
-
- prop = of_get_property(ofdev->node, "chip-delay", NULL);
- if (prop)
- fun->chip_delay = *prop;
- else
- fun->chip_delay = 50;
- ret = fun_chip_init(fun);
+ ret = fun_chip_init(fun, ofdev->node, &io_res);
if (ret)
goto err2;
@@ -251,6 +268,7 @@ static int __devexit fun_remove(struct of_device *ofdev)
struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
nand_release(&fun->mtd);
+ kfree(fun->mtd.name);
if (fun->rnb_gpio >= 0)
gpio_free(fun->rnb_gpio);
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c
new file mode 100644
index 00000000000..8f902e75aa8
--- /dev/null
+++ b/drivers/mtd/nand/gpio.c
@@ -0,0 +1,375 @@
+/*
+ * drivers/mtd/nand/gpio.c
+ *
+ * Updated, and converted to generic GPIO based driver by Russell King.
+ *
+ * Written by Ben Dooks <ben@simtec.co.uk>
+ * Based on 2.4 version by Mark Whittaker
+ *
+ * © 2004 Simtec Electronics
+ *
+ * Device driver for NAND connected via GPIO
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand-gpio.h>
+
+struct gpiomtd {
+ void __iomem *io_sync;
+ struct mtd_info mtd_info;
+ struct nand_chip nand_chip;
+ struct gpio_nand_platdata plat;
+};
+
+#define gpio_nand_getpriv(x) container_of(x, struct gpiomtd, mtd_info)
+
+
+#ifdef CONFIG_ARM
+/* gpio_nand_dosync()
+ *
+ * Make sure the GPIO state changes occur in-order with writes to NAND
+ * memory region.
+ * Needed on PXA due to bus-reordering within the SoC itself (see section on
+ * I/O ordering in PXA manual (section 2.3, p35)
+ */
+static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
+{
+ unsigned long tmp;
+
+ if (gpiomtd->io_sync) {
+ /*
+ * Linux memory barriers don't cater for what's required here.
+ * What's required is what's here - a read from a separate
+ * region with a dependency on that read.
+ */
+ tmp = readl(gpiomtd->io_sync);
+ asm volatile("mov %1, %0\n" : "=r" (tmp) : "r" (tmp));
+ }
+}
+#else
+static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
+#endif
+
+static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+
+ gpio_nand_dosync(gpiomtd);
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ gpio_set_value(gpiomtd->plat.gpio_nce, !(ctrl & NAND_NCE));
+ gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE));
+ gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE));
+ gpio_nand_dosync(gpiomtd);
+ }
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
+ gpio_nand_dosync(gpiomtd);
+}
+
+static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ struct nand_chip *this = mtd->priv;
+
+ writesb(this->IO_ADDR_W, buf, len);
+}
+
+static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct nand_chip *this = mtd->priv;
+
+ readsb(this->IO_ADDR_R, buf, len);
+}
+
+static int gpio_nand_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned char read, *p = (unsigned char *) buf;
+ int i, err = 0;
+
+ for (i = 0; i < len; i++) {
+ read = readb(this->IO_ADDR_R);
+ if (read != p[i]) {
+ pr_debug("%s: err at %d (read %04x vs %04x)\n",
+ __func__, i, read, p[i]);
+ err = -EFAULT;
+ }
+ }
+ return err;
+}
+
+static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
+ int len)
+{
+ struct nand_chip *this = mtd->priv;
+
+ if (IS_ALIGNED((unsigned long)buf, 2)) {
+ writesw(this->IO_ADDR_W, buf, len>>1);
+ } else {
+ int i;
+ unsigned short *ptr = (unsigned short *)buf;
+
+ for (i = 0; i < len; i += 2, ptr++)
+ writew(*ptr, this->IO_ADDR_W);
+ }
+}
+
+static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct nand_chip *this = mtd->priv;
+
+ if (IS_ALIGNED((unsigned long)buf, 2)) {
+ readsw(this->IO_ADDR_R, buf, len>>1);
+ } else {
+ int i;
+ unsigned short *ptr = (unsigned short *)buf;
+
+ for (i = 0; i < len; i += 2, ptr++)
+ *ptr = readw(this->IO_ADDR_R);
+ }
+}
+
+static int gpio_nand_verifybuf16(struct mtd_info *mtd, const u_char *buf,
+ int len)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned short read, *p = (unsigned short *) buf;
+ int i, err = 0;
+ len >>= 1;
+
+ for (i = 0; i < len; i++) {
+ read = readw(this->IO_ADDR_R);
+ if (read != p[i]) {
+ pr_debug("%s: err at %d (read %04x vs %04x)\n",
+ __func__, i, read, p[i]);
+ err = -EFAULT;
+ }
+ }
+ return err;
+}
+
+
+static int gpio_nand_devready(struct mtd_info *mtd)
+{
+ struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+ return gpio_get_value(gpiomtd->plat.gpio_rdy);
+}
+
+static int __devexit gpio_nand_remove(struct platform_device *dev)
+{
+ struct gpiomtd *gpiomtd = platform_get_drvdata(dev);
+ struct resource *res;
+
+ nand_release(&gpiomtd->mtd_info);
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+ iounmap(gpiomtd->io_sync);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ iounmap(gpiomtd->nand_chip.IO_ADDR_R);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+ gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
+ gpio_set_value(gpiomtd->plat.gpio_nce, 1);
+
+ gpio_free(gpiomtd->plat.gpio_cle);
+ gpio_free(gpiomtd->plat.gpio_ale);
+ gpio_free(gpiomtd->plat.gpio_nce);
+ if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+ gpio_free(gpiomtd->plat.gpio_nwp);
+ gpio_free(gpiomtd->plat.gpio_rdy);
+
+ kfree(gpiomtd);
+
+ return 0;
+}
+
+static void __iomem *request_and_remap(struct resource *res, size_t size,
+ const char *name, int *err)
+{
+ void __iomem *ptr;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1, name)) {
+ *err = -EBUSY;
+ return NULL;
+ }
+
+ ptr = ioremap(res->start, size);
+ if (!ptr) {
+ release_mem_region(res->start, res->end - res->start + 1);
+ *err = -ENOMEM;
+ }
+ return ptr;
+}
+
+static int __devinit gpio_nand_probe(struct platform_device *dev)
+{
+ struct gpiomtd *gpiomtd;
+ struct nand_chip *this;
+ struct resource *res0, *res1;
+ int ret;
+
+ if (!dev->dev.platform_data)
+ return -EINVAL;
+
+ res0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res0)
+ return -EINVAL;
+
+ gpiomtd = kzalloc(sizeof(*gpiomtd), GFP_KERNEL);
+ if (gpiomtd == NULL) {
+ dev_err(&dev->dev, "failed to create NAND MTD\n");
+ return -ENOMEM;
+ }
+
+ this = &gpiomtd->nand_chip;
+ this->IO_ADDR_R = request_and_remap(res0, 2, "NAND", &ret);
+ if (!this->IO_ADDR_R) {
+ dev_err(&dev->dev, "unable to map NAND\n");
+ goto err_map;
+ }
+
+ res1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
+ if (res1) {
+ gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret);
+ if (!gpiomtd->io_sync) {
+ dev_err(&dev->dev, "unable to map sync NAND\n");
+ goto err_sync;
+ }
+ }
+
+ memcpy(&gpiomtd->plat, dev->dev.platform_data, sizeof(gpiomtd->plat));
+
+ ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE");
+ if (ret)
+ goto err_nce;
+ gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
+ if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
+ ret = gpio_request(gpiomtd->plat.gpio_nwp, "NAND NWP");
+ if (ret)
+ goto err_nwp;
+ gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
+ }
+ ret = gpio_request(gpiomtd->plat.gpio_ale, "NAND ALE");
+ if (ret)
+ goto err_ale;
+ gpio_direction_output(gpiomtd->plat.gpio_ale, 0);
+ ret = gpio_request(gpiomtd->plat.gpio_cle, "NAND CLE");
+ if (ret)
+ goto err_cle;
+ gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
+ ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
+ if (ret)
+ goto err_rdy;
+ gpio_direction_input(gpiomtd->plat.gpio_rdy);
+
+
+ this->IO_ADDR_W = this->IO_ADDR_R;
+ this->ecc.mode = NAND_ECC_SOFT;
+ this->options = gpiomtd->plat.options;
+ this->chip_delay = gpiomtd->plat.chip_delay;
+
+ /* install our routines */
+ this->cmd_ctrl = gpio_nand_cmd_ctrl;
+ this->dev_ready = gpio_nand_devready;
+
+ if (this->options & NAND_BUSWIDTH_16) {
+ this->read_buf = gpio_nand_readbuf16;
+ this->write_buf = gpio_nand_writebuf16;
+ this->verify_buf = gpio_nand_verifybuf16;
+ } else {
+ this->read_buf = gpio_nand_readbuf;
+ this->write_buf = gpio_nand_writebuf;
+ this->verify_buf = gpio_nand_verifybuf;
+ }
+
+ /* set the mtd private data for the nand driver */
+ gpiomtd->mtd_info.priv = this;
+ gpiomtd->mtd_info.owner = THIS_MODULE;
+
+ if (nand_scan(&gpiomtd->mtd_info, 1)) {
+ dev_err(&dev->dev, "no nand chips found?\n");
+ ret = -ENXIO;
+ goto err_wp;
+ }
+
+ if (gpiomtd->plat.adjust_parts)
+ gpiomtd->plat.adjust_parts(&gpiomtd->plat,
+ gpiomtd->mtd_info.size);
+
+ add_mtd_partitions(&gpiomtd->mtd_info, gpiomtd->plat.parts,
+ gpiomtd->plat.num_parts);
+ platform_set_drvdata(dev, gpiomtd);
+
+ return 0;
+
+err_wp:
+ if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+ gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
+ gpio_free(gpiomtd->plat.gpio_rdy);
+err_rdy:
+ gpio_free(gpiomtd->plat.gpio_cle);
+err_cle:
+ gpio_free(gpiomtd->plat.gpio_ale);
+err_ale:
+ if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+ gpio_free(gpiomtd->plat.gpio_nwp);
+err_nwp:
+ gpio_free(gpiomtd->plat.gpio_nce);
+err_nce:
+ iounmap(gpiomtd->io_sync);
+ if (res1)
+ release_mem_region(res1->start, res1->end - res1->start + 1);
+err_sync:
+ iounmap(gpiomtd->nand_chip.IO_ADDR_R);
+ release_mem_region(res0->start, res0->end - res0->start + 1);
+err_map:
+ kfree(gpiomtd);
+ return ret;
+}
+
+static struct platform_driver gpio_nand_driver = {
+ .probe = gpio_nand_probe,
+ .remove = gpio_nand_remove,
+ .driver = {
+ .name = "gpio-nand",
+ },
+};
+
+static int __init gpio_nand_init(void)
+{
+ printk(KERN_INFO "GPIO NAND driver, © 2004 Simtec Electronics\n");
+
+ return platform_driver_register(&gpio_nand_driver);
+}
+
+static void __exit gpio_nand_exit(void)
+{
+ platform_driver_unregister(&gpio_nand_driver);
+}
+
+module_init(gpio_nand_init);
+module_exit(gpio_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("GPIO NAND Driver");
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
new file mode 100644
index 00000000000..21fd4f1c480
--- /dev/null
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -0,0 +1,1077 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Sascha Hauer, 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/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <asm/mach/flash.h>
+#include <mach/mxc_nand.h>
+
+#define DRIVER_NAME "mxc_nand"
+
+/* Addresses for NFC registers */
+#define NFC_BUF_SIZE 0xE00
+#define NFC_BUF_ADDR 0xE04
+#define NFC_FLASH_ADDR 0xE06
+#define NFC_FLASH_CMD 0xE08
+#define NFC_CONFIG 0xE0A
+#define NFC_ECC_STATUS_RESULT 0xE0C
+#define NFC_RSLTMAIN_AREA 0xE0E
+#define NFC_RSLTSPARE_AREA 0xE10
+#define NFC_WRPROT 0xE12
+#define NFC_UNLOCKSTART_BLKADDR 0xE14
+#define NFC_UNLOCKEND_BLKADDR 0xE16
+#define NFC_NF_WRPRST 0xE18
+#define NFC_CONFIG1 0xE1A
+#define NFC_CONFIG2 0xE1C
+
+/* Addresses for NFC RAM BUFFER Main area 0 */
+#define MAIN_AREA0 0x000
+#define MAIN_AREA1 0x200
+#define MAIN_AREA2 0x400
+#define MAIN_AREA3 0x600
+
+/* Addresses for NFC SPARE BUFFER Spare area 0 */
+#define SPARE_AREA0 0x800
+#define SPARE_AREA1 0x810
+#define SPARE_AREA2 0x820
+#define SPARE_AREA3 0x830
+
+/* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register
+ * for Command operation */
+#define NFC_CMD 0x1
+
+/* Set INT to 0, FADD to 1, rest to 0 in NFC_CONFIG2 Register
+ * for Address operation */
+#define NFC_ADDR 0x2
+
+/* Set INT to 0, FDI to 1, rest to 0 in NFC_CONFIG2 Register
+ * for Input operation */
+#define NFC_INPUT 0x4
+
+/* Set INT to 0, FDO to 001, rest to 0 in NFC_CONFIG2 Register
+ * for Data Output operation */
+#define NFC_OUTPUT 0x8
+
+/* Set INT to 0, FD0 to 010, rest to 0 in NFC_CONFIG2 Register
+ * for Read ID operation */
+#define NFC_ID 0x10
+
+/* Set INT to 0, FDO to 100, rest to 0 in NFC_CONFIG2 Register
+ * for Read Status operation */
+#define NFC_STATUS 0x20
+
+/* Set INT to 1, rest to 0 in NFC_CONFIG2 Register for Read
+ * Status operation */
+#define NFC_INT 0x8000
+
+#define NFC_SP_EN (1 << 2)
+#define NFC_ECC_EN (1 << 3)
+#define NFC_INT_MSK (1 << 4)
+#define NFC_BIG (1 << 5)
+#define NFC_RST (1 << 6)
+#define NFC_CE (1 << 7)
+#define NFC_ONE_CYCLE (1 << 8)
+
+struct mxc_nand_host {
+ struct mtd_info mtd;
+ struct nand_chip nand;
+ struct mtd_partition *parts;
+ struct device *dev;
+
+ void __iomem *regs;
+ int spare_only;
+ int status_request;
+ int pagesize_2k;
+ uint16_t col_addr;
+ struct clk *clk;
+ int clk_act;
+ int irq;
+
+ wait_queue_head_t irq_waitq;
+};
+
+/* Define delays in microsec for NAND device operations */
+#define TROP_US_DELAY 2000
+/* Macros to get byte and bit positions of ECC */
+#define COLPOS(x) ((x) >> 3)
+#define BITPOS(x) ((x) & 0xf)
+
+/* Define single bit Error positions in Main & Spare area */
+#define MAIN_SINGLEBIT_ERROR 0x4
+#define SPARE_SINGLEBIT_ERROR 0x1
+
+/* OOB placement block for use with hardware ecc generation */
+static struct nand_ecclayout nand_hw_eccoob_8 = {
+ .eccbytes = 5,
+ .eccpos = {6, 7, 8, 9, 10},
+ .oobfree = {{0, 5}, {11, 5}, }
+};
+
+static struct nand_ecclayout nand_hw_eccoob_16 = {
+ .eccbytes = 5,
+ .eccpos = {6, 7, 8, 9, 10},
+ .oobfree = {{0, 6}, {12, 4}, }
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
+#endif
+
+static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
+{
+ struct mxc_nand_host *host = dev_id;
+
+ uint16_t tmp;
+
+ tmp = readw(host->regs + NFC_CONFIG1);
+ tmp |= NFC_INT_MSK; /* Disable interrupt */
+ writew(tmp, host->regs + NFC_CONFIG1);
+
+ wake_up(&host->irq_waitq);
+
+ return IRQ_HANDLED;
+}
+
+/* This function polls the NANDFC to wait for the basic operation to
+ * complete by checking the INT bit of config2 register.
+ */
+static void wait_op_done(struct mxc_nand_host *host, int max_retries,
+ uint16_t param, int useirq)
+{
+ uint32_t tmp;
+
+ if (useirq) {
+ if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) {
+
+ tmp = readw(host->regs + NFC_CONFIG1);
+ tmp &= ~NFC_INT_MSK; /* Enable interrupt */
+ writew(tmp, host->regs + NFC_CONFIG1);
+
+ wait_event(host->irq_waitq,
+ readw(host->regs + NFC_CONFIG2) & NFC_INT);
+
+ tmp = readw(host->regs + NFC_CONFIG2);
+ tmp &= ~NFC_INT;
+ writew(tmp, host->regs + NFC_CONFIG2);
+ }
+ } else {
+ while (max_retries-- > 0) {
+ if (readw(host->regs + NFC_CONFIG2) & NFC_INT) {
+ tmp = readw(host->regs + NFC_CONFIG2);
+ tmp &= ~NFC_INT;
+ writew(tmp, host->regs + NFC_CONFIG2);
+ break;
+ }
+ udelay(1);
+ }
+ if (max_retries <= 0)
+ DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n",
+ __func__, param);
+ }
+}
+
+/* This function issues the specified command to the NAND device and
+ * waits for completion. */
+static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq)
+{
+ DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
+
+ writew(cmd, host->regs + NFC_FLASH_CMD);
+ writew(NFC_CMD, host->regs + NFC_CONFIG2);
+
+ /* Wait for operation to complete */
+ wait_op_done(host, TROP_US_DELAY, cmd, useirq);
+}
+
+/* This function sends an address (or partial address) to the
+ * NAND device. The address is used to select the source/destination for
+ * a NAND command. */
+static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
+{
+ DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast);
+
+ writew(addr, host->regs + NFC_FLASH_ADDR);
+ writew(NFC_ADDR, host->regs + NFC_CONFIG2);
+
+ /* Wait for operation to complete */
+ wait_op_done(host, TROP_US_DELAY, addr, islast);
+}
+
+/* This function requests the NANDFC to initate the transfer
+ * of data currently in the NANDFC RAM buffer to the NAND device. */
+static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
+ int spare_only)
+{
+ DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", spare_only);
+
+ /* NANDFC buffer 0 is used for page read/write */
+ writew(buf_id, host->regs + NFC_BUF_ADDR);
+
+ /* Configure spare or page+spare access */
+ if (!host->pagesize_2k) {
+ uint16_t config1 = readw(host->regs + NFC_CONFIG1);
+ if (spare_only)
+ config1 |= NFC_SP_EN;
+ else
+ config1 &= ~(NFC_SP_EN);
+ writew(config1, host->regs + NFC_CONFIG1);
+ }
+
+ writew(NFC_INPUT, host->regs + NFC_CONFIG2);
+
+ /* Wait for operation to complete */
+ wait_op_done(host, TROP_US_DELAY, spare_only, true);
+}
+
+/* Requests NANDFC to initated the transfer of data from the
+ * NAND device into in the NANDFC ram buffer. */
+static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,
+ int spare_only)
+{
+ DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only);
+
+ /* NANDFC buffer 0 is used for page read/write */
+ writew(buf_id, host->regs + NFC_BUF_ADDR);
+
+ /* Configure spare or page+spare access */
+ if (!host->pagesize_2k) {
+ uint32_t config1 = readw(host->regs + NFC_CONFIG1);
+ if (spare_only)
+ config1 |= NFC_SP_EN;
+ else
+ config1 &= ~NFC_SP_EN;
+ writew(config1, host->regs + NFC_CONFIG1);
+ }
+
+ writew(NFC_OUTPUT, host->regs + NFC_CONFIG2);
+
+ /* Wait for operation to complete */
+ wait_op_done(host, TROP_US_DELAY, spare_only, true);
+}
+
+/* Request the NANDFC to perform a read of the NAND device ID. */
+static void send_read_id(struct mxc_nand_host *host)
+{
+ struct nand_chip *this = &host->nand;
+ uint16_t tmp;
+
+ /* NANDFC buffer 0 is used for device ID output */
+ writew(0x0, host->regs + NFC_BUF_ADDR);
+
+ /* Read ID into main buffer */
+ tmp = readw(host->regs + NFC_CONFIG1);
+ tmp &= ~NFC_SP_EN;
+ writew(tmp, host->regs + NFC_CONFIG1);
+
+ writew(NFC_ID, host->regs + NFC_CONFIG2);
+
+ /* Wait for operation to complete */
+ wait_op_done(host, TROP_US_DELAY, 0, true);
+
+ if (this->options & NAND_BUSWIDTH_16) {
+ void __iomem *main_buf = host->regs + MAIN_AREA0;
+ /* compress the ID info */
+ writeb(readb(main_buf + 2), main_buf + 1);
+ writeb(readb(main_buf + 4), main_buf + 2);
+ writeb(readb(main_buf + 6), main_buf + 3);
+ writeb(readb(main_buf + 8), main_buf + 4);
+ writeb(readb(main_buf + 10), main_buf + 5);
+ }
+}
+
+/* This function requests the NANDFC to perform a read of the
+ * NAND device status and returns the current status. */
+static uint16_t get_dev_status(struct mxc_nand_host *host)
+{
+ void __iomem *main_buf = host->regs + MAIN_AREA1;
+ uint32_t store;
+ uint16_t ret, tmp;
+ /* Issue status request to NAND device */
+
+ /* store the main area1 first word, later do recovery */
+ store = readl(main_buf);
+ /* NANDFC buffer 1 is used for device status to prevent
+ * corruption of read/write buffer on status requests. */
+ writew(1, host->regs + NFC_BUF_ADDR);
+
+ /* Read status into main buffer */
+ tmp = readw(host->regs + NFC_CONFIG1);
+ tmp &= ~NFC_SP_EN;
+ writew(tmp, host->regs + NFC_CONFIG1);
+
+ writew(NFC_STATUS, host->regs + NFC_CONFIG2);
+
+ /* Wait for operation to complete */
+ wait_op_done(host, TROP_US_DELAY, 0, true);
+
+ /* Status is placed in first word of main buffer */
+ /* get status, then recovery area 1 data */
+ ret = readw(main_buf);
+ writel(store, main_buf);
+
+ return ret;
+}
+
+/* This functions is used by upper layer to checks if device is ready */
+static int mxc_nand_dev_ready(struct mtd_info *mtd)
+{
+ /*
+ * NFC handles R/B internally. Therefore, this function
+ * always returns status as ready.
+ */
+ return 1;
+}
+
+static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ /*
+ * If HW ECC is enabled, we turn it on during init. There is
+ * no need to enable again here.
+ */
+}
+
+static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct mxc_nand_host *host = nand_chip->priv;
+
+ /*
+ * 1-Bit errors are automatically corrected in HW. No need for
+ * additional correction. 2-Bit errors cannot be corrected by
+ * HW ECC, so we need to return failure
+ */
+ uint16_t ecc_status = readw(host->regs + NFC_ECC_STATUS_RESULT);
+
+ if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
+ DEBUG(MTD_DEBUG_LEVEL0,
+ "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
+{
+ return 0;
+}
+
+static u_char mxc_nand_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct mxc_nand_host *host = nand_chip->priv;
+ uint8_t ret = 0;
+ uint16_t col, rd_word;
+ uint16_t __iomem *main_buf = host->regs + MAIN_AREA0;
+ uint16_t __iomem *spare_buf = host->regs + SPARE_AREA0;
+
+ /* Check for status request */
+ if (host->status_request)
+ return get_dev_status(host) & 0xFF;
+
+ /* Get column for 16-bit access */
+ col = host->col_addr >> 1;
+
+ /* If we are accessing the spare region */
+ if (host->spare_only)
+ rd_word = readw(&spare_buf[col]);
+ else
+ rd_word = readw(&main_buf[col]);
+
+ /* Pick upper/lower byte of word from RAM buffer */
+ if (host->col_addr & 0x1)
+ ret = (rd_word >> 8) & 0xFF;
+ else
+ ret = rd_word & 0xFF;
+
+ /* Update saved column address */
+ host->col_addr++;
+
+ return ret;
+}
+
+static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct mxc_nand_host *host = nand_chip->priv;
+ uint16_t col, rd_word, ret;
+ uint16_t __iomem *p;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "mxc_nand_read_word(col = %d)\n", host->col_addr);
+
+ col = host->col_addr;
+ /* Adjust saved column address */
+ if (col < mtd->writesize && host->spare_only)
+ col += mtd->writesize;
+
+ if (col < mtd->writesize)
+ p = (host->regs + MAIN_AREA0) + (col >> 1);
+ else
+ p = (host->regs + SPARE_AREA0) + ((col - mtd->writesize) >> 1);
+
+ if (col & 1) {
+ rd_word = readw(p);
+ ret = (rd_word >> 8) & 0xff;
+ rd_word = readw(&p[1]);
+ ret |= (rd_word << 8) & 0xff00;
+
+ } else
+ ret = readw(p);
+
+ /* Update saved column address */
+ host->col_addr = col + 2;
+
+ return ret;
+}
+
+/* Write data of length len to buffer buf. The data to be
+ * written on NAND Flash is first copied to RAMbuffer. After the Data Input
+ * Operation by the NFC, the data is written to NAND Flash */
+static void mxc_nand_write_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct mxc_nand_host *host = nand_chip->priv;
+ int n, col, i = 0;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr,
+ len);
+
+ col = host->col_addr;
+
+ /* Adjust saved column address */
+ if (col < mtd->writesize && host->spare_only)
+ col += mtd->writesize;
+
+ n = mtd->writesize + mtd->oobsize - col;
+ n = min(len, n);
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n);
+
+ while (n) {
+ void __iomem *p;
+
+ if (col < mtd->writesize)
+ p = host->regs + MAIN_AREA0 + (col & ~3);
+ else
+ p = host->regs + SPARE_AREA0 -
+ mtd->writesize + (col & ~3);
+
+ DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__,
+ __LINE__, p);
+
+ if (((col | (int)&buf[i]) & 3) || n < 16) {
+ uint32_t data = 0;
+
+ if (col & 3 || n < 4)
+ data = readl(p);
+
+ switch (col & 3) {
+ case 0:
+ if (n) {
+ data = (data & 0xffffff00) |
+ (buf[i++] << 0);
+ n--;
+ col++;
+ }
+ case 1:
+ if (n) {
+ data = (data & 0xffff00ff) |
+ (buf[i++] << 8);
+ n--;
+ col++;
+ }
+ case 2:
+ if (n) {
+ data = (data & 0xff00ffff) |
+ (buf[i++] << 16);
+ n--;
+ col++;
+ }
+ case 3:
+ if (n) {
+ data = (data & 0x00ffffff) |
+ (buf[i++] << 24);
+ n--;
+ col++;
+ }
+ }
+
+ writel(data, p);
+ } else {
+ int m = mtd->writesize - col;
+
+ if (col >= mtd->writesize)
+ m += mtd->oobsize;
+
+ m = min(n, m) & ~3;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s:%d: n = %d, m = %d, i = %d, col = %d\n",
+ __func__, __LINE__, n, m, i, col);
+
+ memcpy(p, &buf[i], m);
+ col += m;
+ i += m;
+ n -= m;
+ }
+ }
+ /* Update saved column address */
+ host->col_addr = col;
+}
+
+/* Read the data buffer from the NAND Flash. To read the data from NAND
+ * Flash first the data output cycle is initiated by the NFC, which copies
+ * the data to RAMbuffer. This data of length len is then copied to buffer buf.
+ */
+static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct mxc_nand_host *host = nand_chip->priv;
+ int n, col, i = 0;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len);
+
+ col = host->col_addr;
+
+ /* Adjust saved column address */
+ if (col < mtd->writesize && host->spare_only)
+ col += mtd->writesize;
+
+ n = mtd->writesize + mtd->oobsize - col;
+ n = min(len, n);
+
+ while (n) {
+ void __iomem *p;
+
+ if (col < mtd->writesize)
+ p = host->regs + MAIN_AREA0 + (col & ~3);
+ else
+ p = host->regs + SPARE_AREA0 -
+ mtd->writesize + (col & ~3);
+
+ if (((col | (int)&buf[i]) & 3) || n < 16) {
+ uint32_t data;
+
+ data = readl(p);
+ switch (col & 3) {
+ case 0:
+ if (n) {
+ buf[i++] = (uint8_t) (data);
+ n--;
+ col++;
+ }
+ case 1:
+ if (n) {
+ buf[i++] = (uint8_t) (data >> 8);
+ n--;
+ col++;
+ }
+ case 2:
+ if (n) {
+ buf[i++] = (uint8_t) (data >> 16);
+ n--;
+ col++;
+ }
+ case 3:
+ if (n) {
+ buf[i++] = (uint8_t) (data >> 24);
+ n--;
+ col++;
+ }
+ }
+ } else {
+ int m = mtd->writesize - col;
+
+ if (col >= mtd->writesize)
+ m += mtd->oobsize;
+
+ m = min(n, m) & ~3;
+ memcpy(&buf[i], p, m);
+ col += m;
+ i += m;
+ n -= m;
+ }
+ }
+ /* Update saved column address */
+ host->col_addr = col;
+
+}
+
+/* Used by the upper layer to verify the data in NAND Flash
+ * with the data in the buf. */
+static int mxc_nand_verify_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ return -EFAULT;
+}
+
+/* This function is used by upper layer for select and
+ * deselect of the NAND chip */
+static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct mxc_nand_host *host = nand_chip->priv;
+
+#ifdef CONFIG_MTD_NAND_MXC_FORCE_CE
+ if (chip > 0) {
+ DEBUG(MTD_DEBUG_LEVEL0,
+ "ERROR: Illegal chip select (chip = %d)\n", chip);
+ return;
+ }
+
+ if (chip == -1) {
+ writew(readw(host->regs + NFC_CONFIG1) & ~NFC_CE,
+ host->regs + NFC_CONFIG1);
+ return;
+ }
+
+ writew(readw(host->regs + NFC_CONFIG1) | NFC_CE,
+ host->regs + NFC_CONFIG1);
+#endif
+
+ switch (chip) {
+ case -1:
+ /* Disable the NFC clock */
+ if (host->clk_act) {
+ clk_disable(host->clk);
+ host->clk_act = 0;
+ }
+ break;
+ case 0:
+ /* Enable the NFC clock */
+ if (!host->clk_act) {
+ clk_enable(host->clk);
+ host->clk_act = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Used by the upper layer to write command to NAND Flash for
+ * different operations to be carried out on NAND Flash */
+static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ int column, int page_addr)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct mxc_nand_host *host = nand_chip->priv;
+ int useirq = true;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
+ command, column, page_addr);
+
+ /* Reset command state information */
+ host->status_request = false;
+
+ /* Command pre-processing step */
+ switch (command) {
+
+ case NAND_CMD_STATUS:
+ host->col_addr = 0;
+ host->status_request = true;
+ break;
+
+ case NAND_CMD_READ0:
+ host->col_addr = column;
+ host->spare_only = false;
+ useirq = false;
+ break;
+
+ case NAND_CMD_READOOB:
+ host->col_addr = column;
+ host->spare_only = true;
+ useirq = false;
+ if (host->pagesize_2k)
+ command = NAND_CMD_READ0; /* only READ0 is valid */
+ break;
+
+ case NAND_CMD_SEQIN:
+ if (column >= mtd->writesize) {
+ /*
+ * FIXME: before send SEQIN command for write OOB,
+ * We must read one page out.
+ * For K9F1GXX has no READ1 command to set current HW
+ * pointer to spare area, we must write the whole page
+ * including OOB together.
+ */
+ if (host->pagesize_2k)
+ /* call ourself to read a page */
+ mxc_nand_command(mtd, NAND_CMD_READ0, 0,
+ page_addr);
+
+ host->col_addr = column - mtd->writesize;
+ host->spare_only = true;
+
+ /* Set program pointer to spare region */
+ if (!host->pagesize_2k)
+ send_cmd(host, NAND_CMD_READOOB, false);
+ } else {
+ host->spare_only = false;
+ host->col_addr = column;
+
+ /* Set program pointer to page start */
+ if (!host->pagesize_2k)
+ send_cmd(host, NAND_CMD_READ0, false);
+ }
+ useirq = false;
+ break;
+
+ case NAND_CMD_PAGEPROG:
+ send_prog_page(host, 0, host->spare_only);
+
+ if (host->pagesize_2k) {
+ /* data in 4 areas datas */
+ send_prog_page(host, 1, host->spare_only);
+ send_prog_page(host, 2, host->spare_only);
+ send_prog_page(host, 3, host->spare_only);
+ }
+
+ break;
+
+ case NAND_CMD_ERASE1:
+ useirq = false;
+ break;
+ }
+
+ /* Write out the command to the device. */
+ send_cmd(host, command, useirq);
+
+ /* Write out column address, if necessary */
+ if (column != -1) {
+ /*
+ * MXC NANDFC can only perform full page+spare or
+ * spare-only read/write. When the upper layers
+ * layers perform a read/write buf operation,
+ * we will used the saved column adress to index into
+ * the full page.
+ */
+ send_addr(host, 0, page_addr == -1);
+ if (host->pagesize_2k)
+ /* another col addr cycle for 2k page */
+ send_addr(host, 0, false);
+ }
+
+ /* Write out page address, if necessary */
+ if (page_addr != -1) {
+ /* paddr_0 - p_addr_7 */
+ send_addr(host, (page_addr & 0xff), false);
+
+ if (host->pagesize_2k) {
+ send_addr(host, (page_addr >> 8) & 0xFF, false);
+ if (mtd->size >= 0x40000000)
+ send_addr(host, (page_addr >> 16) & 0xff, true);
+ } else {
+ /* One more address cycle for higher density devices */
+ if (mtd->size >= 0x4000000) {
+ /* paddr_8 - paddr_15 */
+ send_addr(host, (page_addr >> 8) & 0xff, false);
+ send_addr(host, (page_addr >> 16) & 0xff, true);
+ } else
+ /* paddr_8 - paddr_15 */
+ send_addr(host, (page_addr >> 8) & 0xff, true);
+ }
+ }
+
+ /* Command post-processing step */
+ switch (command) {
+
+ case NAND_CMD_RESET:
+ break;
+
+ case NAND_CMD_READOOB:
+ case NAND_CMD_READ0:
+ if (host->pagesize_2k) {
+ /* send read confirm command */
+ send_cmd(host, NAND_CMD_READSTART, true);
+ /* read for each AREA */
+ send_read_page(host, 0, host->spare_only);
+ send_read_page(host, 1, host->spare_only);
+ send_read_page(host, 2, host->spare_only);
+ send_read_page(host, 3, host->spare_only);
+ } else
+ send_read_page(host, 0, host->spare_only);
+ break;
+
+ case NAND_CMD_READID:
+ send_read_id(host);
+ break;
+
+ case NAND_CMD_PAGEPROG:
+ break;
+
+ case NAND_CMD_STATUS:
+ break;
+
+ case NAND_CMD_ERASE2:
+ break;
+ }
+}
+
+static int __init mxcnd_probe(struct platform_device *pdev)
+{
+ struct nand_chip *this;
+ struct mtd_info *mtd;
+ struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
+ struct mxc_nand_host *host;
+ struct resource *res;
+ uint16_t tmp;
+ int err = 0, nr_parts = 0;
+
+ /* Allocate memory for MTD device structure and private data */
+ host = kzalloc(sizeof(struct mxc_nand_host), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ host->dev = &pdev->dev;
+ /* structures must be linked */
+ this = &host->nand;
+ mtd = &host->mtd;
+ mtd->priv = this;
+ mtd->owner = THIS_MODULE;
+
+ /* 50 us command delay time */
+ this->chip_delay = 5;
+
+ this->priv = host;
+ this->dev_ready = mxc_nand_dev_ready;
+ this->cmdfunc = mxc_nand_command;
+ this->select_chip = mxc_nand_select_chip;
+ this->read_byte = mxc_nand_read_byte;
+ this->read_word = mxc_nand_read_word;
+ this->write_buf = mxc_nand_write_buf;
+ this->read_buf = mxc_nand_read_buf;
+ this->verify_buf = mxc_nand_verify_buf;
+
+ host->clk = clk_get(&pdev->dev, "nfc_clk");
+ if (IS_ERR(host->clk))
+ goto eclk;
+
+ clk_enable(host->clk);
+ host->clk_act = 1;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENODEV;
+ goto eres;
+ }
+
+ host->regs = ioremap(res->start, res->end - res->start + 1);
+ if (!host->regs) {
+ err = -EIO;
+ goto eres;
+ }
+
+ tmp = readw(host->regs + NFC_CONFIG1);
+ tmp |= NFC_INT_MSK;
+ writew(tmp, host->regs + NFC_CONFIG1);
+
+ init_waitqueue_head(&host->irq_waitq);
+
+ host->irq = platform_get_irq(pdev, 0);
+
+ err = request_irq(host->irq, mxc_nfc_irq, 0, "mxc_nd", host);
+ if (err)
+ goto eirq;
+
+ if (pdata->hw_ecc) {
+ this->ecc.calculate = mxc_nand_calculate_ecc;
+ this->ecc.hwctl = mxc_nand_enable_hwecc;
+ this->ecc.correct = mxc_nand_correct_data;
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.size = 512;
+ this->ecc.bytes = 3;
+ this->ecc.layout = &nand_hw_eccoob_8;
+ tmp = readw(host->regs + NFC_CONFIG1);
+ tmp |= NFC_ECC_EN;
+ writew(tmp, host->regs + NFC_CONFIG1);
+ } else {
+ this->ecc.size = 512;
+ this->ecc.bytes = 3;
+ this->ecc.layout = &nand_hw_eccoob_8;
+ this->ecc.mode = NAND_ECC_SOFT;
+ tmp = readw(host->regs + NFC_CONFIG1);
+ tmp &= ~NFC_ECC_EN;
+ writew(tmp, host->regs + NFC_CONFIG1);
+ }
+
+ /* Reset NAND */
+ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+ /* preset operation */
+ /* Unlock the internal RAM Buffer */
+ writew(0x2, host->regs + NFC_CONFIG);
+
+ /* Blocks to be unlocked */
+ writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR);
+ writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR);
+
+ /* Unlock Block Command for given address range */
+ writew(0x4, host->regs + NFC_WRPROT);
+
+ /* NAND bus width determines access funtions used by upper layer */
+ if (pdata->width == 2) {
+ this->options |= NAND_BUSWIDTH_16;
+ this->ecc.layout = &nand_hw_eccoob_16;
+ }
+
+ host->pagesize_2k = 0;
+
+ /* Scan to find existence of the device */
+ if (nand_scan(mtd, 1)) {
+ DEBUG(MTD_DEBUG_LEVEL0,
+ "MXC_ND: Unable to find any NAND device.\n");
+ err = -ENXIO;
+ goto escan;
+ }
+
+ /* Register the partitions */
+#ifdef CONFIG_MTD_PARTITIONS
+ nr_parts =
+ parse_mtd_partitions(mtd, part_probes, &host->parts, 0);
+ if (nr_parts > 0)
+ add_mtd_partitions(mtd, host->parts, nr_parts);
+ else
+#endif
+ {
+ pr_info("Registering %s as whole device\n", mtd->name);
+ add_mtd_device(mtd);
+ }
+
+ platform_set_drvdata(pdev, host);
+
+ return 0;
+
+escan:
+ free_irq(host->irq, NULL);
+eirq:
+ iounmap(host->regs);
+eres:
+ clk_put(host->clk);
+eclk:
+ kfree(host);
+
+ return err;
+}
+
+static int __devexit mxcnd_remove(struct platform_device *pdev)
+{
+ struct mxc_nand_host *host = platform_get_drvdata(pdev);
+
+ clk_put(host->clk);
+
+ platform_set_drvdata(pdev, NULL);
+
+ nand_release(&host->mtd);
+ free_irq(host->irq, NULL);
+ iounmap(host->regs);
+ kfree(host);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mtd_info *info = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n");
+ if (info)
+ ret = info->suspend(info);
+
+ /* Disable the NFC clock */
+ clk_disable(nfc_clk); /* FIXME */
+
+ return ret;
+}
+
+static int mxcnd_resume(struct platform_device *pdev)
+{
+ struct mtd_info *info = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n");
+ /* Enable the NFC clock */
+ clk_enable(nfc_clk); /* FIXME */
+
+ if (info)
+ info->resume(info);
+
+ return ret;
+}
+
+#else
+# define mxcnd_suspend NULL
+# define mxcnd_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver mxcnd_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .remove = __exit_p(mxcnd_remove),
+ .suspend = mxcnd_suspend,
+ .resume = mxcnd_resume,
+};
+
+static int __init mxc_nd_init(void)
+{
+ /* Register the device driver structure. */
+ pr_info("MXC MTD nand Driver\n");
+ if (platform_driver_probe(&mxcnd_driver, mxcnd_probe) != 0) {
+ printk(KERN_ERR "Driver register failed for mxcnd_driver\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit mxc_nd_cleanup(void)
+{
+ /* Unregister the device structure */
+ platform_driver_unregister(&mxcnd_driver);
+}
+
+module_init(mxc_nd_init);
+module_exit(mxc_nd_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC NAND MTD driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index d1129bae6c2..0a9c9cd33f9 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -801,9 +801,9 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
* nand_read_subpage - [REPLACABLE] software ecc based sub-page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
- * @dataofs offset of requested data within the page
- * @readlen data length
- * @buf: buffer to store read data
+ * @data_offs: offset of requested data within the page
+ * @readlen: data length
+ * @bufpoi: buffer to store read data
*/
static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
{
@@ -2042,7 +2042,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
return -EINVAL;
}
- instr->fail_addr = 0xffffffff;
+ instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
/* Grab the lock and see if the device is available */
nand_get_device(chip, mtd, FL_ERASING);
@@ -2318,6 +2318,12 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
/* Select the device */
chip->select_chip(mtd, 0);
+ /*
+ * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
+ * after power-up
+ */
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
@@ -2488,6 +2494,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
+ /* See comment in nand_get_flash_type for reset */
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index 918a806a847..868147acce2 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -1,13 +1,18 @@
/*
- * This file contains an ECC algorithm from Toshiba that detects and
- * corrects 1 bit errors in a 256 byte block of data.
+ * This file contains an ECC algorithm that detects and corrects 1 bit
+ * errors in a 256 byte block of data.
*
* drivers/mtd/nand/nand_ecc.c
*
- * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
- * Toshiba America Electronics Components, Inc.
+ * Copyright © 2008 Koninklijke Philips Electronics NV.
+ * Author: Frans Meulenbroeks
*
- * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de>
+ * Completely replaces the previous ECC implementation which was written by:
+ * Steven J. Hill (sjhill@realitydiluted.com)
+ * Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Information on how this algorithm works and how it was developed
+ * can be found in Documentation/mtd/nand_ecc.txt
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -23,174 +28,475 @@
* with this file; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
- * As a special exception, if other files instantiate templates or use
- * macros or inline functions from these files, or you compile these
- * files and link them with other works to produce a work based on these
- * files, these files do not by themselves cause the resulting work to be
- * covered by the GNU General Public License. However the source code for
- * these files must still be made available in accordance with section (3)
- * of the GNU General Public License.
- *
- * This exception does not invalidate any other reasons why a work based on
- * this file might be covered by the GNU General Public License.
*/
+/*
+ * The STANDALONE macro is useful when running the code outside the kernel
+ * e.g. when running the code in a testbed or a benchmark program.
+ * When STANDALONE is used, the module related macros are commented out
+ * as well as the linux include files.
+ * Instead a private definition of mtd_info is given to satisfy the compiler
+ * (the code does not use mtd_info, so the code does not care)
+ */
+#ifndef STANDALONE
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
+#include <asm/byteorder.h>
+#else
+#include <stdint.h>
+struct mtd_info;
+#define EXPORT_SYMBOL(x) /* x */
+
+#define MODULE_LICENSE(x) /* x */
+#define MODULE_AUTHOR(x) /* x */
+#define MODULE_DESCRIPTION(x) /* x */
+
+#define printk printf
+#define KERN_ERR ""
+#endif
+
+/*
+ * invparity is a 256 byte table that contains the odd parity
+ * for each byte. So if the number of bits in a byte is even,
+ * the array element is 1, and when the number of bits is odd
+ * the array eleemnt is 0.
+ */
+static const char invparity[256] = {
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
+};
+
+/*
+ * bitsperbyte contains the number of bits per byte
+ * this is only used for testing and repairing parity
+ * (a precalculated value slightly improves performance)
+ */
+static const char bitsperbyte[256] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+};
/*
- * Pre-calculated 256-way 1 byte column parity
+ * addressbits is a lookup table to filter out the bits from the xor-ed
+ * ecc data that identify the faulty location.
+ * this is only used for repairing parity
+ * see the comments in nand_correct_data for more details
*/
-static const u_char nand_ecc_precalc_table[] = {
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+static const char addressbits[256] = {
+ 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+ 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+ 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+ 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+ 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+ 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+ 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+ 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+ 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+ 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+ 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+ 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+ 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+ 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+ 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+ 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+ 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+ 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+ 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+ 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+ 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+ 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+ 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+ 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+ 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+ 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+ 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+ 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+ 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+ 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+ 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+ 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
};
/**
- * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
+ * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
+ * block
* @mtd: MTD block structure
- * @dat: raw data
- * @ecc_code: buffer for ECC
+ * @buf: input buffer with raw data
+ * @code: output buffer with ECC
*/
-int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+ unsigned char *code)
{
- uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
int i;
+ const uint32_t *bp = (uint32_t *)buf;
+ /* 256 or 512 bytes/ecc */
+ const uint32_t eccsize_mult =
+ (((struct nand_chip *)mtd->priv)->ecc.size) >> 8;
+ uint32_t cur; /* current value in buffer */
+ /* rp0..rp15..rp17 are the various accumulated parities (per byte) */
+ uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
+ uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
+ uint32_t uninitialized_var(rp17); /* to make compiler happy */
+ uint32_t par; /* the cumulative parity for all data */
+ uint32_t tmppar; /* the cumulative parity for this iteration;
+ for rp12, rp14 and rp16 at the end of the
+ loop */
+
+ par = 0;
+ rp4 = 0;
+ rp6 = 0;
+ rp8 = 0;
+ rp10 = 0;
+ rp12 = 0;
+ rp14 = 0;
+ rp16 = 0;
+
+ /*
+ * The loop is unrolled a number of times;
+ * This avoids if statements to decide on which rp value to update
+ * Also we process the data by longwords.
+ * Note: passing unaligned data might give a performance penalty.
+ * It is assumed that the buffers are aligned.
+ * tmppar is the cumulative sum of this iteration.
+ * needed for calculating rp12, rp14, rp16 and par
+ * also used as a performance improvement for rp6, rp8 and rp10
+ */
+ for (i = 0; i < eccsize_mult << 2; i++) {
+ cur = *bp++;
+ tmppar = cur;
+ rp4 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp6 ^= tmppar;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp4 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp8 ^= tmppar;
- /* Initialize variables */
- reg1 = reg2 = reg3 = 0;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp4 ^= cur;
+ rp6 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp6 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp4 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp10 ^= tmppar;
- /* Build up column parity */
- for(i = 0; i < 256; i++) {
- /* Get CP0 - CP5 from table */
- idx = nand_ecc_precalc_table[*dat++];
- reg1 ^= (idx & 0x3f);
+ cur = *bp++;
+ tmppar ^= cur;
+ rp4 ^= cur;
+ rp6 ^= cur;
+ rp8 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp6 ^= cur;
+ rp8 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp4 ^= cur;
+ rp8 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp8 ^= cur;
- /* All bit XOR = 1 ? */
- if (idx & 0x40) {
- reg3 ^= (uint8_t) i;
- reg2 ^= ~((uint8_t) i);
- }
+ cur = *bp++;
+ tmppar ^= cur;
+ rp4 ^= cur;
+ rp6 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp6 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+ rp4 ^= cur;
+ cur = *bp++;
+ tmppar ^= cur;
+
+ par ^= tmppar;
+ if ((i & 0x1) == 0)
+ rp12 ^= tmppar;
+ if ((i & 0x2) == 0)
+ rp14 ^= tmppar;
+ if (eccsize_mult == 2 && (i & 0x4) == 0)
+ rp16 ^= tmppar;
}
- /* Create non-inverted ECC code from line parity */
- tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */
- tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
- tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
- tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
- tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
- tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
- tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
- tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
-
- tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */
- tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
- tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
- tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
- tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
- tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
- tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
- tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
-
- /* Calculate final ECC code */
-#ifdef CONFIG_MTD_NAND_ECC_SMC
- ecc_code[0] = ~tmp2;
- ecc_code[1] = ~tmp1;
+ /*
+ * handle the fact that we use longword operations
+ * we'll bring rp4..rp14..rp16 back to single byte entities by
+ * shifting and xoring first fold the upper and lower 16 bits,
+ * then the upper and lower 8 bits.
+ */
+ rp4 ^= (rp4 >> 16);
+ rp4 ^= (rp4 >> 8);
+ rp4 &= 0xff;
+ rp6 ^= (rp6 >> 16);
+ rp6 ^= (rp6 >> 8);
+ rp6 &= 0xff;
+ rp8 ^= (rp8 >> 16);
+ rp8 ^= (rp8 >> 8);
+ rp8 &= 0xff;
+ rp10 ^= (rp10 >> 16);
+ rp10 ^= (rp10 >> 8);
+ rp10 &= 0xff;
+ rp12 ^= (rp12 >> 16);
+ rp12 ^= (rp12 >> 8);
+ rp12 &= 0xff;
+ rp14 ^= (rp14 >> 16);
+ rp14 ^= (rp14 >> 8);
+ rp14 &= 0xff;
+ if (eccsize_mult == 2) {
+ rp16 ^= (rp16 >> 16);
+ rp16 ^= (rp16 >> 8);
+ rp16 &= 0xff;
+ }
+
+ /*
+ * we also need to calculate the row parity for rp0..rp3
+ * This is present in par, because par is now
+ * rp3 rp3 rp2 rp2 in little endian and
+ * rp2 rp2 rp3 rp3 in big endian
+ * as well as
+ * rp1 rp0 rp1 rp0 in little endian and
+ * rp0 rp1 rp0 rp1 in big endian
+ * First calculate rp2 and rp3
+ */
+#ifdef __BIG_ENDIAN
+ rp2 = (par >> 16);
+ rp2 ^= (rp2 >> 8);
+ rp2 &= 0xff;
+ rp3 = par & 0xffff;
+ rp3 ^= (rp3 >> 8);
+ rp3 &= 0xff;
#else
- ecc_code[0] = ~tmp1;
- ecc_code[1] = ~tmp2;
+ rp3 = (par >> 16);
+ rp3 ^= (rp3 >> 8);
+ rp3 &= 0xff;
+ rp2 = par & 0xffff;
+ rp2 ^= (rp2 >> 8);
+ rp2 &= 0xff;
#endif
- ecc_code[2] = ((~reg1) << 2) | 0x03;
- return 0;
-}
-EXPORT_SYMBOL(nand_calculate_ecc);
+ /* reduce par to 16 bits then calculate rp1 and rp0 */
+ par ^= (par >> 16);
+#ifdef __BIG_ENDIAN
+ rp0 = (par >> 8) & 0xff;
+ rp1 = (par & 0xff);
+#else
+ rp1 = (par >> 8) & 0xff;
+ rp0 = (par & 0xff);
+#endif
-static inline int countbits(uint32_t byte)
-{
- int res = 0;
+ /* finally reduce par to 8 bits */
+ par ^= (par >> 8);
+ par &= 0xff;
- for (;byte; byte >>= 1)
- res += byte & 0x01;
- return res;
+ /*
+ * and calculate rp5..rp15..rp17
+ * note that par = rp4 ^ rp5 and due to the commutative property
+ * of the ^ operator we can say:
+ * rp5 = (par ^ rp4);
+ * The & 0xff seems superfluous, but benchmarking learned that
+ * leaving it out gives slightly worse results. No idea why, probably
+ * it has to do with the way the pipeline in pentium is organized.
+ */
+ rp5 = (par ^ rp4) & 0xff;
+ rp7 = (par ^ rp6) & 0xff;
+ rp9 = (par ^ rp8) & 0xff;
+ rp11 = (par ^ rp10) & 0xff;
+ rp13 = (par ^ rp12) & 0xff;
+ rp15 = (par ^ rp14) & 0xff;
+ if (eccsize_mult == 2)
+ rp17 = (par ^ rp16) & 0xff;
+
+ /*
+ * Finally calculate the ecc bits.
+ * Again here it might seem that there are performance optimisations
+ * possible, but benchmarks showed that on the system this is developed
+ * the code below is the fastest
+ */
+#ifdef CONFIG_MTD_NAND_ECC_SMC
+ code[0] =
+ (invparity[rp7] << 7) |
+ (invparity[rp6] << 6) |
+ (invparity[rp5] << 5) |
+ (invparity[rp4] << 4) |
+ (invparity[rp3] << 3) |
+ (invparity[rp2] << 2) |
+ (invparity[rp1] << 1) |
+ (invparity[rp0]);
+ code[1] =
+ (invparity[rp15] << 7) |
+ (invparity[rp14] << 6) |
+ (invparity[rp13] << 5) |
+ (invparity[rp12] << 4) |
+ (invparity[rp11] << 3) |
+ (invparity[rp10] << 2) |
+ (invparity[rp9] << 1) |
+ (invparity[rp8]);
+#else
+ code[1] =
+ (invparity[rp7] << 7) |
+ (invparity[rp6] << 6) |
+ (invparity[rp5] << 5) |
+ (invparity[rp4] << 4) |
+ (invparity[rp3] << 3) |
+ (invparity[rp2] << 2) |
+ (invparity[rp1] << 1) |
+ (invparity[rp0]);
+ code[0] =
+ (invparity[rp15] << 7) |
+ (invparity[rp14] << 6) |
+ (invparity[rp13] << 5) |
+ (invparity[rp12] << 4) |
+ (invparity[rp11] << 3) |
+ (invparity[rp10] << 2) |
+ (invparity[rp9] << 1) |
+ (invparity[rp8]);
+#endif
+ if (eccsize_mult == 1)
+ code[2] =
+ (invparity[par & 0xf0] << 7) |
+ (invparity[par & 0x0f] << 6) |
+ (invparity[par & 0xcc] << 5) |
+ (invparity[par & 0x33] << 4) |
+ (invparity[par & 0xaa] << 3) |
+ (invparity[par & 0x55] << 2) |
+ 3;
+ else
+ code[2] =
+ (invparity[par & 0xf0] << 7) |
+ (invparity[par & 0x0f] << 6) |
+ (invparity[par & 0xcc] << 5) |
+ (invparity[par & 0x33] << 4) |
+ (invparity[par & 0xaa] << 3) |
+ (invparity[par & 0x55] << 2) |
+ (invparity[rp17] << 1) |
+ (invparity[rp16] << 0);
+ return 0;
}
+EXPORT_SYMBOL(nand_calculate_ecc);
/**
* nand_correct_data - [NAND Interface] Detect and correct bit error(s)
* @mtd: MTD block structure
- * @dat: raw data read from the chip
+ * @buf: raw data read from the chip
* @read_ecc: ECC from the chip
* @calc_ecc: the ECC calculated from raw data
*
- * Detect and correct a 1 bit error for 256 byte block
+ * Detect and correct a 1 bit error for 256/512 byte block
*/
-int nand_correct_data(struct mtd_info *mtd, u_char *dat,
- u_char *read_ecc, u_char *calc_ecc)
+int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
+ unsigned char *read_ecc, unsigned char *calc_ecc)
{
- uint8_t s0, s1, s2;
+ unsigned char b0, b1, b2;
+ unsigned char byte_addr, bit_addr;
+ /* 256 or 512 bytes/ecc */
+ const uint32_t eccsize_mult =
+ (((struct nand_chip *)mtd->priv)->ecc.size) >> 8;
+ /*
+ * b0 to b2 indicate which bit is faulty (if any)
+ * we might need the xor result more than once,
+ * so keep them in a local var
+ */
#ifdef CONFIG_MTD_NAND_ECC_SMC
- s0 = calc_ecc[0] ^ read_ecc[0];
- s1 = calc_ecc[1] ^ read_ecc[1];
- s2 = calc_ecc[2] ^ read_ecc[2];
+ b0 = read_ecc[0] ^ calc_ecc[0];
+ b1 = read_ecc[1] ^ calc_ecc[1];
#else
- s1 = calc_ecc[0] ^ read_ecc[0];
- s0 = calc_ecc[1] ^ read_ecc[1];
- s2 = calc_ecc[2] ^ read_ecc[2];
+ b0 = read_ecc[1] ^ calc_ecc[1];
+ b1 = read_ecc[0] ^ calc_ecc[0];
#endif
- if ((s0 | s1 | s2) == 0)
- return 0;
-
- /* Check for a single bit error */
- if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
- ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
- ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
+ b2 = read_ecc[2] ^ calc_ecc[2];
- uint32_t byteoffs, bitnum;
+ /* check if there are any bitfaults */
- byteoffs = (s1 << 0) & 0x80;
- byteoffs |= (s1 << 1) & 0x40;
- byteoffs |= (s1 << 2) & 0x20;
- byteoffs |= (s1 << 3) & 0x10;
+ /* repeated if statements are slightly more efficient than switch ... */
+ /* ordered in order of likelihood */
- byteoffs |= (s0 >> 4) & 0x08;
- byteoffs |= (s0 >> 3) & 0x04;
- byteoffs |= (s0 >> 2) & 0x02;
- byteoffs |= (s0 >> 1) & 0x01;
-
- bitnum = (s2 >> 5) & 0x04;
- bitnum |= (s2 >> 4) & 0x02;
- bitnum |= (s2 >> 3) & 0x01;
-
- dat[byteoffs] ^= (1 << bitnum);
+ if ((b0 | b1 | b2) == 0)
+ return 0; /* no error */
+ if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
+ (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
+ ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
+ (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
+ /* single bit error */
+ /*
+ * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty
+ * byte, cp 5/3/1 indicate the faulty bit.
+ * A lookup table (called addressbits) is used to filter
+ * the bits from the byte they are in.
+ * A marginal optimisation is possible by having three
+ * different lookup tables.
+ * One as we have now (for b0), one for b2
+ * (that would avoid the >> 1), and one for b1 (with all values
+ * << 4). However it was felt that introducing two more tables
+ * hardly justify the gain.
+ *
+ * The b2 shift is there to get rid of the lowest two bits.
+ * We could also do addressbits[b2] >> 1 but for the
+ * performace it does not make any difference
+ */
+ if (eccsize_mult == 1)
+ byte_addr = (addressbits[b1] << 4) + addressbits[b0];
+ else
+ byte_addr = (addressbits[b2 & 0x3] << 8) +
+ (addressbits[b1] << 4) + addressbits[b0];
+ bit_addr = addressbits[b2 >> 2];
+ /* flip the bit */
+ buf[byte_addr] ^= (1 << bit_addr);
return 1;
- }
- if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
- return 1;
+ }
+ /* count nr of bits; use table lookup, faster than calculating it */
+ if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
+ return 1; /* error in ecc data; no action needed */
- return -EBADMSG;
+ printk(KERN_ERR "uncorrectable error : ");
+ return -1;
}
EXPORT_SYMBOL(nand_correct_data);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
+MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
MODULE_DESCRIPTION("Generic NAND ECC support");
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 556e8131ecd..ae7c57781a6 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -38,7 +38,6 @@
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/random.h>
-#include <asm/div64.h>
/* Default simulator parameters values */
#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index a64ad15b8fd..c0fa9c9edf0 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -115,55 +115,11 @@ enum {
STATE_PIO_WRITING,
};
-struct pxa3xx_nand_timing {
- unsigned int tCH; /* Enable signal hold time */
- unsigned int tCS; /* Enable signal setup time */
- unsigned int tWH; /* ND_nWE high duration */
- unsigned int tWP; /* ND_nWE pulse time */
- unsigned int tRH; /* ND_nRE high duration */
- unsigned int tRP; /* ND_nRE pulse width */
- unsigned int tR; /* ND_nWE high to ND_nRE low for read */
- unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */
- unsigned int tAR; /* ND_ALE low to ND_nRE low delay */
-};
-
-struct pxa3xx_nand_cmdset {
- uint16_t read1;
- uint16_t read2;
- uint16_t program;
- uint16_t read_status;
- uint16_t read_id;
- uint16_t erase;
- uint16_t reset;
- uint16_t lock;
- uint16_t unlock;
- uint16_t lock_status;
-};
-
-struct pxa3xx_nand_flash {
- struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
- struct pxa3xx_nand_cmdset *cmdset;
-
- uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
- uint32_t page_size; /* Page size in bytes (PAGE_SZ) */
- uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */
- uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */
- uint32_t num_blocks; /* Number of physical blocks in Flash */
- uint32_t chip_id;
-
- /* NOTE: these are automatically calculated, do not define */
- size_t oob_size;
- size_t read_id_bytes;
-
- unsigned int col_addr_cycles;
- unsigned int row_addr_cycles;
-};
-
struct pxa3xx_nand_info {
struct nand_chip nand_chip;
struct platform_device *pdev;
- struct pxa3xx_nand_flash *flash_info;
+ const struct pxa3xx_nand_flash *flash_info;
struct clk *clk;
void __iomem *mmio_base;
@@ -202,12 +158,20 @@ struct pxa3xx_nand_info {
uint32_t ndcb0;
uint32_t ndcb1;
uint32_t ndcb2;
+
+ /* calculated from pxa3xx_nand_flash data */
+ size_t oob_size;
+ size_t read_id_bytes;
+
+ unsigned int col_addr_cycles;
+ unsigned int row_addr_cycles;
};
static int use_dma = 1;
module_param(use_dma, bool, 0444);
MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW");
+#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN
static struct pxa3xx_nand_cmdset smallpage_cmdset = {
.read1 = 0x0000,
.read2 = 0x0050,
@@ -291,11 +255,35 @@ static struct pxa3xx_nand_flash micron1GbX16 = {
.chip_id = 0xb12c,
};
+static struct pxa3xx_nand_timing stm2GbX16_timing = {
+ .tCH = 10,
+ .tCS = 35,
+ .tWH = 15,
+ .tWP = 25,
+ .tRH = 15,
+ .tRP = 25,
+ .tR = 25000,
+ .tWHR = 60,
+ .tAR = 10,
+};
+
+static struct pxa3xx_nand_flash stm2GbX16 = {
+ .timing = &stm2GbX16_timing,
+ .page_per_block = 64,
+ .page_size = 2048,
+ .flash_width = 16,
+ .dfc_width = 16,
+ .num_blocks = 2048,
+ .chip_id = 0xba20,
+};
+
static struct pxa3xx_nand_flash *builtin_flash_types[] = {
&samsung512MbX16,
&micron1GbX8,
&micron1GbX16,
+ &stm2GbX16,
};
+#endif /* CONFIG_MTD_NAND_PXA3xx_BUILTIN */
#define NDTR0_tCH(c) (min((c), 7) << 19)
#define NDTR0_tCS(c) (min((c), 7) << 16)
@@ -312,7 +300,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = {
#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1)
static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
- struct pxa3xx_nand_timing *t)
+ const struct pxa3xx_nand_timing *t)
{
unsigned long nand_clk = clk_get_rate(info->clk);
uint32_t ndtr0, ndtr1;
@@ -354,8 +342,8 @@ static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event)
static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
uint16_t cmd, int column, int page_addr)
{
- struct pxa3xx_nand_flash *f = info->flash_info;
- struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
+ const struct pxa3xx_nand_flash *f = info->flash_info;
+ const struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
/* calculate data size */
switch (f->page_size) {
@@ -373,14 +361,14 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
info->ndcb1 = 0;
info->ndcb2 = 0;
- info->ndcb0 |= NDCB0_ADDR_CYC(f->row_addr_cycles + f->col_addr_cycles);
+ info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles);
- if (f->col_addr_cycles == 2) {
+ if (info->col_addr_cycles == 2) {
/* large block, 2 cycles for column address
* row address starts from 3rd cycle
*/
info->ndcb1 |= (page_addr << 16) | (column & 0xffff);
- if (f->row_addr_cycles == 3)
+ if (info->row_addr_cycles == 3)
info->ndcb2 = (page_addr >> 16) & 0xff;
} else
/* small block, 1 cycles for column address
@@ -406,7 +394,7 @@ static int prepare_erase_cmd(struct pxa3xx_nand_info *info,
static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
{
- struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
+ const struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
info->ndcb1 = 0;
@@ -641,8 +629,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
int column, int page_addr)
{
struct pxa3xx_nand_info *info = mtd->priv;
- struct pxa3xx_nand_flash *flash_info = info->flash_info;
- struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset;
+ const struct pxa3xx_nand_flash *flash_info = info->flash_info;
+ const struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset;
int ret;
info->use_dma = (use_dma) ? 1 : 0;
@@ -720,7 +708,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
info->use_dma = 0; /* force PIO read */
info->buf_start = 0;
info->buf_count = (command == NAND_CMD_READID) ?
- flash_info->read_id_bytes : 1;
+ info->read_id_bytes : 1;
if (prepare_other_cmd(info, (command == NAND_CMD_READID) ?
cmdset->read_id : cmdset->read_status))
@@ -861,8 +849,8 @@ static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd,
static int __readid(struct pxa3xx_nand_info *info, uint32_t *id)
{
- struct pxa3xx_nand_flash *f = info->flash_info;
- struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
+ const struct pxa3xx_nand_flash *f = info->flash_info;
+ const struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
uint32_t ndcr;
uint8_t id_buff[8];
@@ -891,7 +879,7 @@ fail_timeout:
}
static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
- struct pxa3xx_nand_flash *f)
+ const struct pxa3xx_nand_flash *f)
{
struct platform_device *pdev = info->pdev;
struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
@@ -904,25 +892,25 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
return -EINVAL;
/* calculate flash information */
- f->oob_size = (f->page_size == 2048) ? 64 : 16;
- f->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
+ info->oob_size = (f->page_size == 2048) ? 64 : 16;
+ info->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
/* calculate addressing information */
- f->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
+ info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
if (f->num_blocks * f->page_per_block > 65536)
- f->row_addr_cycles = 3;
+ info->row_addr_cycles = 3;
else
- f->row_addr_cycles = 2;
+ info->row_addr_cycles = 2;
ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
- ndcr |= (f->col_addr_cycles == 2) ? NDCR_RA_START : 0;
+ ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0;
ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;
ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;
ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
- ndcr |= NDCR_RD_ID_CNT(f->read_id_bytes);
+ ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes);
ndcr |= NDCR_SPARE_EN; /* enable spare by default */
info->reg_ndcr = ndcr;
@@ -932,12 +920,27 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
return 0;
}
-static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info)
+static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info,
+ const struct pxa3xx_nand_platform_data *pdata)
{
- struct pxa3xx_nand_flash *f;
- uint32_t id;
+ const struct pxa3xx_nand_flash *f;
+ uint32_t id = -1;
int i;
+ for (i = 0; i<pdata->num_flash; ++i) {
+ f = pdata->flash + i;
+
+ if (pxa3xx_nand_config_flash(info, f))
+ continue;
+
+ if (__readid(info, &id))
+ continue;
+
+ if (id == f->chip_id)
+ return 0;
+ }
+
+#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN
for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) {
f = builtin_flash_types[i];
@@ -951,7 +954,11 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info)
if (id == f->chip_id)
return 0;
}
+#endif
+ dev_warn(&info->pdev->dev,
+ "failed to detect configured nand flash; found %04x instead of\n",
+ id);
return -ENODEV;
}
@@ -1014,7 +1021,7 @@ static struct nand_ecclayout hw_largepage_ecclayout = {
static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
struct pxa3xx_nand_info *info)
{
- struct pxa3xx_nand_flash *f = info->flash_info;
+ const struct pxa3xx_nand_flash *f = info->flash_info;
struct nand_chip *this = &info->nand_chip;
this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0;
@@ -1135,7 +1142,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
goto fail_free_buf;
}
- ret = pxa3xx_nand_detect_flash(info);
+ ret = pxa3xx_nand_detect_flash(info, pdata);
if (ret) {
dev_err(&pdev->dev, "failed to detect flash\n");
ret = -ENODEV;
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
new file mode 100644
index 00000000000..821acb08ff1
--- /dev/null
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -0,0 +1,878 @@
+/*
+ * SuperH FLCTL nand controller
+ *
+ * Copyright © 2008 Renesas Solutions Corp.
+ * Copyright © 2008 Atom Create Engineering Co., Ltd.
+ *
+ * Based on fsl_elbc_nand.c, Copyright © 2006-2007 Freescale Semiconductor
+ *
+ * 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 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
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/sh_flctl.h>
+
+static struct nand_ecclayout flctl_4secc_oob_16 = {
+ .eccbytes = 10,
+ .eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ .oobfree = {
+ {.offset = 12,
+ . length = 4} },
+};
+
+static struct nand_ecclayout flctl_4secc_oob_64 = {
+ .eccbytes = 10,
+ .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57},
+ .oobfree = {
+ {.offset = 60,
+ . length = 4} },
+};
+
+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+
+static struct nand_bbt_descr flctl_4secc_smallpage = {
+ .options = NAND_BBT_SCAN2NDPAGE,
+ .offs = 11,
+ .len = 1,
+ .pattern = scan_ff_pattern,
+};
+
+static struct nand_bbt_descr flctl_4secc_largepage = {
+ .options = 0,
+ .offs = 58,
+ .len = 2,
+ .pattern = scan_ff_pattern,
+};
+
+static void empty_fifo(struct sh_flctl *flctl)
+{
+ writel(0x000c0000, FLINTDMACR(flctl)); /* FIFO Clear */
+ writel(0x00000000, FLINTDMACR(flctl)); /* Clear Error flags */
+}
+
+static void start_translation(struct sh_flctl *flctl)
+{
+ writeb(TRSTRT, FLTRCR(flctl));
+}
+
+static void wait_completion(struct sh_flctl *flctl)
+{
+ uint32_t timeout = LOOP_TIMEOUT_MAX;
+
+ while (timeout--) {
+ if (readb(FLTRCR(flctl)) & TREND) {
+ writeb(0x0, FLTRCR(flctl));
+ return;
+ }
+ udelay(1);
+ }
+
+ printk(KERN_ERR "wait_completion(): Timeout occured \n");
+ writeb(0x0, FLTRCR(flctl));
+}
+
+static void set_addr(struct mtd_info *mtd, int column, int page_addr)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ uint32_t addr = 0;
+
+ if (column == -1) {
+ addr = page_addr; /* ERASE1 */
+ } else if (page_addr != -1) {
+ /* SEQIN, READ0, etc.. */
+ if (flctl->page_size) {
+ addr = column & 0x0FFF;
+ addr |= (page_addr & 0xff) << 16;
+ addr |= ((page_addr >> 8) & 0xff) << 24;
+ /* big than 128MB */
+ if (flctl->rw_ADRCNT == ADRCNT2_E) {
+ uint32_t addr2;
+ addr2 = (page_addr >> 16) & 0xff;
+ writel(addr2, FLADR2(flctl));
+ }
+ } else {
+ addr = column;
+ addr |= (page_addr & 0xff) << 8;
+ addr |= ((page_addr >> 8) & 0xff) << 16;
+ addr |= ((page_addr >> 16) & 0xff) << 24;
+ }
+ }
+ writel(addr, FLADR(flctl));
+}
+
+static void wait_rfifo_ready(struct sh_flctl *flctl)
+{
+ uint32_t timeout = LOOP_TIMEOUT_MAX;
+
+ while (timeout--) {
+ uint32_t val;
+ /* check FIFO */
+ val = readl(FLDTCNTR(flctl)) >> 16;
+ if (val & 0xFF)
+ return;
+ udelay(1);
+ }
+ printk(KERN_ERR "wait_rfifo_ready(): Timeout occured \n");
+}
+
+static void wait_wfifo_ready(struct sh_flctl *flctl)
+{
+ uint32_t len, timeout = LOOP_TIMEOUT_MAX;
+
+ while (timeout--) {
+ /* check FIFO */
+ len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
+ if (len >= 4)
+ return;
+ udelay(1);
+ }
+ printk(KERN_ERR "wait_wfifo_ready(): Timeout occured \n");
+}
+
+static int wait_recfifo_ready(struct sh_flctl *flctl)
+{
+ uint32_t timeout = LOOP_TIMEOUT_MAX;
+ int checked[4];
+ void __iomem *ecc_reg[4];
+ int i;
+ uint32_t data, size;
+
+ memset(checked, 0, sizeof(checked));
+
+ while (timeout--) {
+ size = readl(FLDTCNTR(flctl)) >> 24;
+ if (size & 0xFF)
+ return 0; /* success */
+
+ if (readl(FL4ECCCR(flctl)) & _4ECCFA)
+ return 1; /* can't correct */
+
+ udelay(1);
+ if (!(readl(FL4ECCCR(flctl)) & _4ECCEND))
+ continue;
+
+ /* start error correction */
+ ecc_reg[0] = FL4ECCRESULT0(flctl);
+ ecc_reg[1] = FL4ECCRESULT1(flctl);
+ ecc_reg[2] = FL4ECCRESULT2(flctl);
+ ecc_reg[3] = FL4ECCRESULT3(flctl);
+
+ for (i = 0; i < 3; i++) {
+ data = readl(ecc_reg[i]);
+ if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) {
+ uint8_t org;
+ int index;
+
+ index = data >> 16;
+ org = flctl->done_buff[index];
+ flctl->done_buff[index] = org ^ (data & 0xFF);
+ checked[i] = 1;
+ }
+ }
+
+ writel(0, FL4ECCCR(flctl));
+ }
+
+ printk(KERN_ERR "wait_recfifo_ready(): Timeout occured \n");
+ return 1; /* timeout */
+}
+
+static void wait_wecfifo_ready(struct sh_flctl *flctl)
+{
+ uint32_t timeout = LOOP_TIMEOUT_MAX;
+ uint32_t len;
+
+ while (timeout--) {
+ /* check FLECFIFO */
+ len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
+ if (len >= 4)
+ return;
+ udelay(1);
+ }
+ printk(KERN_ERR "wait_wecfifo_ready(): Timeout occured \n");
+}
+
+static void read_datareg(struct sh_flctl *flctl, int offset)
+{
+ unsigned long data;
+ unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+
+ wait_completion(flctl);
+
+ data = readl(FLDATAR(flctl));
+ *buf = le32_to_cpu(data);
+}
+
+static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+{
+ int i, len_4align;
+ unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+ void *fifo_addr = (void *)FLDTFIFO(flctl);
+
+ len_4align = (rlen + 3) / 4;
+
+ for (i = 0; i < len_4align; i++) {
+ wait_rfifo_ready(flctl);
+ buf[i] = readl(fifo_addr);
+ buf[i] = be32_to_cpu(buf[i]);
+ }
+}
+
+static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff)
+{
+ int i;
+ unsigned long *ecc_buf = (unsigned long *)buff;
+ void *fifo_addr = (void *)FLECFIFO(flctl);
+
+ for (i = 0; i < 4; i++) {
+ if (wait_recfifo_ready(flctl))
+ return 1;
+ ecc_buf[i] = readl(fifo_addr);
+ ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
+ }
+
+ return 0;
+}
+
+static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+{
+ int i, len_4align;
+ unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
+ void *fifo_addr = (void *)FLDTFIFO(flctl);
+
+ len_4align = (rlen + 3) / 4;
+ for (i = 0; i < len_4align; i++) {
+ wait_wfifo_ready(flctl);
+ writel(cpu_to_be32(data[i]), fifo_addr);
+ }
+}
+
+static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ uint32_t flcmncr_val = readl(FLCMNCR(flctl));
+ uint32_t flcmdcr_val, addr_len_bytes = 0;
+
+ /* Set SNAND bit if page size is 2048byte */
+ if (flctl->page_size)
+ flcmncr_val |= SNAND_E;
+ else
+ flcmncr_val &= ~SNAND_E;
+
+ /* default FLCMDCR val */
+ flcmdcr_val = DOCMD1_E | DOADR_E;
+
+ /* Set for FLCMDCR */
+ switch (cmd) {
+ case NAND_CMD_ERASE1:
+ addr_len_bytes = flctl->erase_ADRCNT;
+ flcmdcr_val |= DOCMD2_E;
+ break;
+ case NAND_CMD_READ0:
+ case NAND_CMD_READOOB:
+ addr_len_bytes = flctl->rw_ADRCNT;
+ flcmdcr_val |= CDSRC_E;
+ break;
+ case NAND_CMD_SEQIN:
+ /* This case is that cmd is READ0 or READ1 or READ00 */
+ flcmdcr_val &= ~DOADR_E; /* ONLY execute 1st cmd */
+ break;
+ case NAND_CMD_PAGEPROG:
+ addr_len_bytes = flctl->rw_ADRCNT;
+ flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
+ break;
+ case NAND_CMD_READID:
+ flcmncr_val &= ~SNAND_E;
+ addr_len_bytes = ADRCNT_1;
+ break;
+ case NAND_CMD_STATUS:
+ case NAND_CMD_RESET:
+ flcmncr_val &= ~SNAND_E;
+ flcmdcr_val &= ~(DOADR_E | DOSR_E);
+ break;
+ default:
+ break;
+ }
+
+ /* Set address bytes parameter */
+ flcmdcr_val |= addr_len_bytes;
+
+ /* Now actually write */
+ writel(flcmncr_val, FLCMNCR(flctl));
+ writel(flcmdcr_val, FLCMDCR(flctl));
+ writel(flcmcdr_val, FLCMCDR(flctl));
+}
+
+static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->read_buf(mtd, p, eccsize);
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ if (flctl->hwecc_cant_correct[i])
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += 0;
+ }
+
+ return 0;
+}
+
+static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ const uint8_t *p = buf;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->write_buf(mtd, p, eccsize);
+}
+
+static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ int sector, page_sectors;
+
+ if (flctl->page_size)
+ page_sectors = 4;
+ else
+ page_sectors = 1;
+
+ writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
+ FLCMNCR(flctl));
+
+ set_cmd_regs(mtd, NAND_CMD_READ0,
+ (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
+
+ for (sector = 0; sector < page_sectors; sector++) {
+ int ret;
+
+ empty_fifo(flctl);
+ writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
+ writel(page_addr << 2 | sector, FLADR(flctl));
+
+ start_translation(flctl);
+ read_fiforeg(flctl, 512, 512 * sector);
+
+ ret = read_ecfiforeg(flctl,
+ &flctl->done_buff[mtd->writesize + 16 * sector]);
+
+ if (ret)
+ flctl->hwecc_cant_correct[sector] = 1;
+
+ writel(0x0, FL4ECCCR(flctl));
+ wait_completion(flctl);
+ }
+ writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
+ FLCMNCR(flctl));
+}
+
+static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+
+ set_cmd_regs(mtd, NAND_CMD_READ0,
+ (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
+
+ empty_fifo(flctl);
+ if (flctl->page_size) {
+ int i;
+ /* In case that the page size is 2k */
+ for (i = 0; i < 16 * 3; i++)
+ flctl->done_buff[i] = 0xFF;
+
+ set_addr(mtd, 3 * 528 + 512, page_addr);
+ writel(16, FLDTCNTR(flctl));
+
+ start_translation(flctl);
+ read_fiforeg(flctl, 16, 16 * 3);
+ wait_completion(flctl);
+ } else {
+ /* In case that the page size is 512b */
+ set_addr(mtd, 512, page_addr);
+ writel(16, FLDTCNTR(flctl));
+
+ start_translation(flctl);
+ read_fiforeg(flctl, 16, 0);
+ wait_completion(flctl);
+ }
+}
+
+static void execmd_write_page_sector(struct mtd_info *mtd)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ int i, page_addr = flctl->seqin_page_addr;
+ int sector, page_sectors;
+
+ if (flctl->page_size)
+ page_sectors = 4;
+ else
+ page_sectors = 1;
+
+ writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
+
+ set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
+ (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
+
+ for (sector = 0; sector < page_sectors; sector++) {
+ empty_fifo(flctl);
+ writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
+ writel(page_addr << 2 | sector, FLADR(flctl));
+
+ start_translation(flctl);
+ write_fiforeg(flctl, 512, 512 * sector);
+
+ for (i = 0; i < 4; i++) {
+ wait_wecfifo_ready(flctl); /* wait for write ready */
+ writel(0xFFFFFFFF, FLECFIFO(flctl));
+ }
+ wait_completion(flctl);
+ }
+
+ writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
+}
+
+static void execmd_write_oob(struct mtd_info *mtd)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ int page_addr = flctl->seqin_page_addr;
+ int sector, page_sectors;
+
+ if (flctl->page_size) {
+ sector = 3;
+ page_sectors = 4;
+ } else {
+ sector = 0;
+ page_sectors = 1;
+ }
+
+ set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
+ (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
+
+ for (; sector < page_sectors; sector++) {
+ empty_fifo(flctl);
+ set_addr(mtd, sector * 528 + 512, page_addr);
+ writel(16, FLDTCNTR(flctl)); /* set read size */
+
+ start_translation(flctl);
+ write_fiforeg(flctl, 16, 16 * sector);
+ wait_completion(flctl);
+ }
+}
+
+static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ uint32_t read_cmd = 0;
+
+ flctl->read_bytes = 0;
+ if (command != NAND_CMD_PAGEPROG)
+ flctl->index = 0;
+
+ switch (command) {
+ case NAND_CMD_READ1:
+ case NAND_CMD_READ0:
+ if (flctl->hwecc) {
+ /* read page with hwecc */
+ execmd_read_page_sector(mtd, page_addr);
+ break;
+ }
+ empty_fifo(flctl);
+ if (flctl->page_size)
+ set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
+ | command);
+ else
+ set_cmd_regs(mtd, command, command);
+
+ set_addr(mtd, 0, page_addr);
+
+ flctl->read_bytes = mtd->writesize + mtd->oobsize;
+ flctl->index += column;
+ goto read_normal_exit;
+
+ case NAND_CMD_READOOB:
+ if (flctl->hwecc) {
+ /* read page with hwecc */
+ execmd_read_oob(mtd, page_addr);
+ break;
+ }
+
+ empty_fifo(flctl);
+ if (flctl->page_size) {
+ set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
+ | NAND_CMD_READ0);
+ set_addr(mtd, mtd->writesize, page_addr);
+ } else {
+ set_cmd_regs(mtd, command, command);
+ set_addr(mtd, 0, page_addr);
+ }
+ flctl->read_bytes = mtd->oobsize;
+ goto read_normal_exit;
+
+ case NAND_CMD_READID:
+ empty_fifo(flctl);
+ set_cmd_regs(mtd, command, command);
+ set_addr(mtd, 0, 0);
+
+ flctl->read_bytes = 4;
+ writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
+ start_translation(flctl);
+ read_datareg(flctl, 0); /* read and end */
+ break;
+
+ case NAND_CMD_ERASE1:
+ flctl->erase1_page_addr = page_addr;
+ break;
+
+ case NAND_CMD_ERASE2:
+ set_cmd_regs(mtd, NAND_CMD_ERASE1,
+ (command << 8) | NAND_CMD_ERASE1);
+ set_addr(mtd, -1, flctl->erase1_page_addr);
+ start_translation(flctl);
+ wait_completion(flctl);
+ break;
+
+ case NAND_CMD_SEQIN:
+ if (!flctl->page_size) {
+ /* output read command */
+ if (column >= mtd->writesize) {
+ column -= mtd->writesize;
+ read_cmd = NAND_CMD_READOOB;
+ } else if (column < 256) {
+ read_cmd = NAND_CMD_READ0;
+ } else {
+ column -= 256;
+ read_cmd = NAND_CMD_READ1;
+ }
+ }
+ flctl->seqin_column = column;
+ flctl->seqin_page_addr = page_addr;
+ flctl->seqin_read_cmd = read_cmd;
+ break;
+
+ case NAND_CMD_PAGEPROG:
+ empty_fifo(flctl);
+ if (!flctl->page_size) {
+ set_cmd_regs(mtd, NAND_CMD_SEQIN,
+ flctl->seqin_read_cmd);
+ set_addr(mtd, -1, -1);
+ writel(0, FLDTCNTR(flctl)); /* set 0 size */
+ start_translation(flctl);
+ wait_completion(flctl);
+ }
+ if (flctl->hwecc) {
+ /* write page with hwecc */
+ if (flctl->seqin_column == mtd->writesize)
+ execmd_write_oob(mtd);
+ else if (!flctl->seqin_column)
+ execmd_write_page_sector(mtd);
+ else
+ printk(KERN_ERR "Invalid address !?\n");
+ break;
+ }
+ set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
+ set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
+ writel(flctl->index, FLDTCNTR(flctl)); /* set write size */
+ start_translation(flctl);
+ write_fiforeg(flctl, flctl->index, 0);
+ wait_completion(flctl);
+ break;
+
+ case NAND_CMD_STATUS:
+ set_cmd_regs(mtd, command, command);
+ set_addr(mtd, -1, -1);
+
+ flctl->read_bytes = 1;
+ writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
+ start_translation(flctl);
+ read_datareg(flctl, 0); /* read and end */
+ break;
+
+ case NAND_CMD_RESET:
+ set_cmd_regs(mtd, command, command);
+ set_addr(mtd, -1, -1);
+
+ writel(0, FLDTCNTR(flctl)); /* set 0 size */
+ start_translation(flctl);
+ wait_completion(flctl);
+ break;
+
+ default:
+ break;
+ }
+ return;
+
+read_normal_exit:
+ writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
+ start_translation(flctl);
+ read_fiforeg(flctl, flctl->read_bytes, 0);
+ wait_completion(flctl);
+ return;
+}
+
+static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ uint32_t flcmncr_val = readl(FLCMNCR(flctl));
+
+ switch (chipnr) {
+ case -1:
+ flcmncr_val &= ~CE0_ENABLE;
+ writel(flcmncr_val, FLCMNCR(flctl));
+ break;
+ case 0:
+ flcmncr_val |= CE0_ENABLE;
+ writel(flcmncr_val, FLCMNCR(flctl));
+ break;
+ default:
+ BUG();
+ }
+}
+
+static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ int i, index = flctl->index;
+
+ for (i = 0; i < len; i++)
+ flctl->done_buff[index + i] = buf[i];
+ flctl->index += len;
+}
+
+static uint8_t flctl_read_byte(struct mtd_info *mtd)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ int index = flctl->index;
+ uint8_t data;
+
+ data = flctl->done_buff[index];
+ flctl->index++;
+ return data;
+}
+
+static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = flctl_read_byte(mtd);
+}
+
+static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (buf[i] != flctl_read_byte(mtd))
+ return -EFAULT;
+ return 0;
+}
+
+static void flctl_register_init(struct sh_flctl *flctl, unsigned long val)
+{
+ writel(val, FLCMNCR(flctl));
+}
+
+static int flctl_chip_init_tail(struct mtd_info *mtd)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ struct nand_chip *chip = &flctl->chip;
+
+ if (mtd->writesize == 512) {
+ flctl->page_size = 0;
+ if (chip->chipsize > (32 << 20)) {
+ /* big than 32MB */
+ flctl->rw_ADRCNT = ADRCNT_4;
+ flctl->erase_ADRCNT = ADRCNT_3;
+ } else if (chip->chipsize > (2 << 16)) {
+ /* big than 128KB */
+ flctl->rw_ADRCNT = ADRCNT_3;
+ flctl->erase_ADRCNT = ADRCNT_2;
+ } else {
+ flctl->rw_ADRCNT = ADRCNT_2;
+ flctl->erase_ADRCNT = ADRCNT_1;
+ }
+ } else {
+ flctl->page_size = 1;
+ if (chip->chipsize > (128 << 20)) {
+ /* big than 128MB */
+ flctl->rw_ADRCNT = ADRCNT2_E;
+ flctl->erase_ADRCNT = ADRCNT_3;
+ } else if (chip->chipsize > (8 << 16)) {
+ /* big than 512KB */
+ flctl->rw_ADRCNT = ADRCNT_4;
+ flctl->erase_ADRCNT = ADRCNT_2;
+ } else {
+ flctl->rw_ADRCNT = ADRCNT_3;
+ flctl->erase_ADRCNT = ADRCNT_1;
+ }
+ }
+
+ if (flctl->hwecc) {
+ if (mtd->writesize == 512) {
+ chip->ecc.layout = &flctl_4secc_oob_16;
+ chip->badblock_pattern = &flctl_4secc_smallpage;
+ } else {
+ chip->ecc.layout = &flctl_4secc_oob_64;
+ chip->badblock_pattern = &flctl_4secc_largepage;
+ }
+
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 10;
+ chip->ecc.read_page = flctl_read_page_hwecc;
+ chip->ecc.write_page = flctl_write_page_hwecc;
+ chip->ecc.mode = NAND_ECC_HW;
+
+ /* 4 symbols ECC enabled */
+ writel(readl(FLCMNCR(flctl)) | _4ECCEN | ECCPOS2 | ECCPOS_02,
+ FLCMNCR(flctl));
+ } else {
+ chip->ecc.mode = NAND_ECC_SOFT;
+ }
+
+ return 0;
+}
+
+static int __init flctl_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct sh_flctl *flctl;
+ struct mtd_info *flctl_mtd;
+ struct nand_chip *nand;
+ struct sh_flctl_platform_data *pdata;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL) {
+ printk(KERN_ERR "sh_flctl platform_data not found.\n");
+ return -ENODEV;
+ }
+
+ flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
+ if (!flctl) {
+ printk(KERN_ERR "Unable to allocate NAND MTD dev structure.\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ printk(KERN_ERR "%s: resource not found.\n", __func__);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ flctl->reg = ioremap(res->start, res->end - res->start + 1);
+ if (flctl->reg == NULL) {
+ printk(KERN_ERR "%s: ioremap error.\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, flctl);
+ flctl_mtd = &flctl->mtd;
+ nand = &flctl->chip;
+ flctl_mtd->priv = nand;
+ flctl->hwecc = pdata->has_hwecc;
+
+ flctl_register_init(flctl, pdata->flcmncr_val);
+
+ nand->options = NAND_NO_AUTOINCR;
+
+ /* Set address of hardware control function */
+ /* 20 us command delay time */
+ nand->chip_delay = 20;
+
+ nand->read_byte = flctl_read_byte;
+ nand->write_buf = flctl_write_buf;
+ nand->read_buf = flctl_read_buf;
+ nand->verify_buf = flctl_verify_buf;
+ nand->select_chip = flctl_select_chip;
+ nand->cmdfunc = flctl_cmdfunc;
+
+ ret = nand_scan_ident(flctl_mtd, 1);
+ if (ret)
+ goto err;
+
+ ret = flctl_chip_init_tail(flctl_mtd);
+ if (ret)
+ goto err;
+
+ ret = nand_scan_tail(flctl_mtd);
+ if (ret)
+ goto err;
+
+ add_mtd_partitions(flctl_mtd, pdata->parts, pdata->nr_parts);
+
+ return 0;
+
+err:
+ kfree(flctl);
+ return ret;
+}
+
+static int __exit flctl_remove(struct platform_device *pdev)
+{
+ struct sh_flctl *flctl = platform_get_drvdata(pdev);
+
+ nand_release(&flctl->mtd);
+ kfree(flctl);
+
+ return 0;
+}
+
+static struct platform_driver flctl_driver = {
+ .probe = flctl_probe,
+ .remove = flctl_remove,
+ .driver = {
+ .name = "sh_flctl",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init flctl_nand_init(void)
+{
+ return platform_driver_register(&flctl_driver);
+}
+
+static void __exit flctl_nand_cleanup(void)
+{
+ platform_driver_unregister(&flctl_driver);
+}
+
+module_init(flctl_nand_init);
+module_exit(flctl_nand_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yoshihiro Shimoda");
+MODULE_DESCRIPTION("SuperH FLCTL driver");
+MODULE_ALIAS("platform:sh_flctl");
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c
deleted file mode 100644
index bbf492e6830..00000000000
--- a/drivers/mtd/nand/toto.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * drivers/mtd/nand/toto.c
- *
- * Copyright (c) 2003 Texas Instruments
- *
- * Derived from drivers/mtd/autcpu12.c
- *
- * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.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.
- *
- * Overview:
- * This is a device driver for the NAND flash device found on the
- * TI fido board. It supports 32MiB and 64MiB cards
- */
-
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <asm/io.h>
-#include <asm/arch/hardware.h>
-#include <asm/sizes.h>
-#include <asm/arch/toto.h>
-#include <asm/arch-omap1510/hardware.h>
-#include <asm/arch/gpio.h>
-
-#define CONFIG_NAND_WORKAROUND 1
-
-/*
- * MTD structure for TOTO board
- */
-static struct mtd_info *toto_mtd = NULL;
-
-static unsigned long toto_io_base = OMAP_FLASH_1_BASE;
-
-/*
- * Define partitions for flash devices
- */
-
-static struct mtd_partition partition_info64M[] = {
- { .name = "toto kernel partition 1",
- .offset = 0,
- .size = 2 * SZ_1M },
- { .name = "toto file sys partition 2",
- .offset = 2 * SZ_1M,
- .size = 14 * SZ_1M },
- { .name = "toto user partition 3",
- .offset = 16 * SZ_1M,
- .size = 16 * SZ_1M },
- { .name = "toto devboard extra partition 4",
- .offset = 32 * SZ_1M,
- .size = 32 * SZ_1M },
-};
-
-static struct mtd_partition partition_info32M[] = {
- { .name = "toto kernel partition 1",
- .offset = 0,
- .size = 2 * SZ_1M },
- { .name = "toto file sys partition 2",
- .offset = 2 * SZ_1M,
- .size = 14 * SZ_1M },
- { .name = "toto user partition 3",
- .offset = 16 * SZ_1M,
- .size = 16 * SZ_1M },
-};
-
-#define NUM_PARTITIONS32M 3
-#define NUM_PARTITIONS64M 4
-
-/*
- * hardware specific access to control-lines
- *
- * ctrl:
- * NAND_NCE: bit 0 -> bit 14 (0x4000)
- * NAND_CLE: bit 1 -> bit 12 (0x1000)
- * NAND_ALE: bit 2 -> bit 1 (0x0002)
- */
-static void toto_hwcontrol(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
-{
- struct nand_chip *chip = mtd->priv;
-
- if (ctrl & NAND_CTRL_CHANGE) {
- unsigned long bits;
-
- /* hopefully enough time for tc make proceding write to clear */
- udelay(1);
-
- bits = (~ctrl & NAND_NCE) << 14;
- bits |= (ctrl & NAND_CLE) << 12;
- bits |= (ctrl & NAND_ALE) >> 1;
-
-#warning Wild guess as gpiosetout() is nowhere defined in the kernel source - tglx
- gpiosetout(0x5002, bits);
-
-#ifdef CONFIG_NAND_WORKAROUND
- /* "some" dev boards busted, blue wired to rts2 :( */
- rts2setout(2, (ctrl & NAND_CLE) << 1);
-#endif
- /* allow time to ensure gpio state to over take memory write */
- udelay(1);
- }
-
- if (cmd != NAND_CMD_NONE)
- writeb(cmd, chip->IO_ADDR_W);
-}
-
-/*
- * Main initialization routine
- */
-static int __init toto_init(void)
-{
- struct nand_chip *this;
- int err = 0;
-
- /* Allocate memory for MTD device structure and private data */
- toto_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
- if (!toto_mtd) {
- printk(KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n");
- err = -ENOMEM;
- goto out;
- }
-
- /* Get pointer to private data */
- this = (struct nand_chip *)(&toto_mtd[1]);
-
- /* Initialize structures */
- memset(toto_mtd, 0, sizeof(struct mtd_info));
- memset(this, 0, sizeof(struct nand_chip));
-
- /* Link the private data with the MTD structure */
- toto_mtd->priv = this;
- toto_mtd->owner = THIS_MODULE;
-
- /* Set address of NAND IO lines */
- this->IO_ADDR_R = toto_io_base;
- this->IO_ADDR_W = toto_io_base;
- this->cmd_ctrl = toto_hwcontrol;
- this->dev_ready = NULL;
- /* 25 us command delay time */
- this->chip_delay = 30;
- this->ecc.mode = NAND_ECC_SOFT;
-
- /* Scan to find existance of the device */
- if (nand_scan(toto_mtd, 1)) {
- err = -ENXIO;
- goto out_mtd;
- }
-
- /* Register the partitions */
- switch (toto_mtd->size) {
- case SZ_64M:
- add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M);
- break;
- case SZ_32M:
- add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M);
- break;
- default:{
- printk(KERN_WARNING "Unsupported Nand device\n");
- err = -ENXIO;
- goto out_buf;
- }
- }
-
- gpioreserve(NAND_MASK); /* claim our gpios */
- archflashwp(0, 0); /* open up flash for writing */
-
- goto out;
-
- out_mtd:
- kfree(toto_mtd);
- out:
- return err;
-}
-
-module_init(toto_init);
-
-/*
- * Clean up routine
- */
-static void __exit toto_cleanup(void)
-{
- /* Release resources, unregister device */
- nand_release(toto_mtd);
-
- /* Free the MTD device structure */
- kfree(toto_mtd);
-
- /* stop flash writes */
- archflashwp(0, 1);
-
- /* release gpios to system */
- gpiorelease(NAND_MASK);
-}
-
-module_exit(toto_cleanup);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Richard Woodruff <r-woodruff2@ti.com>");
-MODULE_DESCRIPTION("Glue layer for NAND flash on toto board");
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 4f80c2fd89a..9e45b3f39c0 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -20,7 +20,6 @@
#include <linux/mtd/partitions.h>
int __devinit of_mtd_parse_partitions(struct device *dev,
- struct mtd_info *mtd,
struct device_node *node,
struct mtd_partition **pparts)
{
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index cb41cbca64f..79fa79e8f8d 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -27,8 +27,16 @@ config MTD_ONENAND_GENERIC
help
Support for OneNAND flash via platform device driver.
+config MTD_ONENAND_OMAP2
+ tristate "OneNAND on OMAP2/OMAP3 support"
+ depends on MTD_ONENAND && (ARCH_OMAP2 || ARCH_OMAP3)
+ help
+ Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
+ via the GPMC memory controller.
+
config MTD_ONENAND_OTP
bool "OneNAND OTP Support"
+ select HAVE_MTD_OTP
help
One Block of the NAND Flash Array memory is reserved as
a One-Time Programmable Block memory area.
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile
index 4d2eacfd7e1..64b6cc61a52 100644
--- a/drivers/mtd/onenand/Makefile
+++ b/drivers/mtd/onenand/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o
# Board specific.
obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o
+obj-$(CONFIG_MTD_ONENAND_OMAP2) += omap2.o
# Simulator
obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
new file mode 100644
index 00000000000..8387e05daae
--- /dev/null
+++ b/drivers/mtd/onenand/omap2.c
@@ -0,0 +1,802 @@
+/*
+ * linux/drivers/mtd/onenand/omap2.c
+ *
+ * OneNAND driver for OMAP2 / OMAP3
+ *
+ * Copyright © 2005-2006 Nokia Corporation
+ *
+ * Author: Jarkko Lavinen <jarkko.lavinen@nokia.com> and Juha Yrjölä
+ * IRQ and DMA support written by Timo Teras
+ *
+ * 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.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/mach/flash.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/onenand.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/gpmc.h>
+#include <asm/arch/pm.h>
+
+#include <linux/dma-mapping.h>
+#include <asm/dma-mapping.h>
+#include <asm/arch/dma.h>
+
+#include <asm/arch/board.h>
+
+#define DRIVER_NAME "omap2-onenand"
+
+#define ONENAND_IO_SIZE SZ_128K
+#define ONENAND_BUFRAM_SIZE (1024 * 5)
+
+struct omap2_onenand {
+ struct platform_device *pdev;
+ int gpmc_cs;
+ unsigned long phys_base;
+ int gpio_irq;
+ struct mtd_info mtd;
+ struct mtd_partition *parts;
+ struct onenand_chip onenand;
+ struct completion irq_done;
+ struct completion dma_done;
+ int dma_channel;
+ int freq;
+ int (*setup)(void __iomem *base, int freq);
+};
+
+static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
+{
+ struct omap2_onenand *c = data;
+
+ complete(&c->dma_done);
+}
+
+static irqreturn_t omap2_onenand_interrupt(int irq, void *dev_id)
+{
+ struct omap2_onenand *c = dev_id;
+
+ complete(&c->irq_done);
+
+ return IRQ_HANDLED;
+}
+
+static inline unsigned short read_reg(struct omap2_onenand *c, int reg)
+{
+ return readw(c->onenand.base + reg);
+}
+
+static inline void write_reg(struct omap2_onenand *c, unsigned short value,
+ int reg)
+{
+ writew(value, c->onenand.base + reg);
+}
+
+static void wait_err(char *msg, int state, unsigned int ctrl, unsigned int intr)
+{
+ printk(KERN_ERR "onenand_wait: %s! state %d ctrl 0x%04x intr 0x%04x\n",
+ msg, state, ctrl, intr);
+}
+
+static void wait_warn(char *msg, int state, unsigned int ctrl,
+ unsigned int intr)
+{
+ printk(KERN_WARNING "onenand_wait: %s! state %d ctrl 0x%04x "
+ "intr 0x%04x\n", msg, state, ctrl, intr);
+}
+
+static int omap2_onenand_wait(struct mtd_info *mtd, int state)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ unsigned int intr = 0;
+ unsigned int ctrl;
+ unsigned long timeout;
+ u32 syscfg;
+
+ if (state == FL_RESETING) {
+ int i;
+
+ for (i = 0; i < 20; i++) {
+ udelay(1);
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ if (intr & ONENAND_INT_MASTER)
+ break;
+ }
+ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+ if (ctrl & ONENAND_CTRL_ERROR) {
+ wait_err("controller error", state, ctrl, intr);
+ return -EIO;
+ }
+ if (!(intr & ONENAND_INT_RESET)) {
+ wait_err("timeout", state, ctrl, intr);
+ return -EIO;
+ }
+ return 0;
+ }
+
+ if (state != FL_READING) {
+ int result;
+
+ /* Turn interrupts on */
+ syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
+ if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) {
+ syscfg |= ONENAND_SYS_CFG1_IOBE;
+ write_reg(c, syscfg, ONENAND_REG_SYS_CFG1);
+ if (cpu_is_omap34xx())
+ /* Add a delay to let GPIO settle */
+ syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
+ }
+
+ INIT_COMPLETION(c->irq_done);
+ if (c->gpio_irq) {
+ result = omap_get_gpio_datain(c->gpio_irq);
+ if (result == -1) {
+ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ wait_err("gpio error", state, ctrl, intr);
+ return -EIO;
+ }
+ } else
+ result = 0;
+ if (result == 0) {
+ int retry_cnt = 0;
+retry:
+ result = wait_for_completion_timeout(&c->irq_done,
+ msecs_to_jiffies(20));
+ if (result == 0) {
+ /* Timeout after 20ms */
+ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+ if (ctrl & ONENAND_CTRL_ONGO) {
+ /*
+ * The operation seems to be still going
+ * so give it some more time.
+ */
+ retry_cnt += 1;
+ if (retry_cnt < 3)
+ goto retry;
+ intr = read_reg(c,
+ ONENAND_REG_INTERRUPT);
+ wait_err("timeout", state, ctrl, intr);
+ return -EIO;
+ }
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ if ((intr & ONENAND_INT_MASTER) == 0)
+ wait_warn("timeout", state, ctrl, intr);
+ }
+ }
+ } else {
+ int retry_cnt = 0;
+
+ /* Turn interrupts off */
+ syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
+ syscfg &= ~ONENAND_SYS_CFG1_IOBE;
+ write_reg(c, syscfg, ONENAND_REG_SYS_CFG1);
+
+ timeout = jiffies + msecs_to_jiffies(20);
+ while (1) {
+ if (time_before(jiffies, timeout)) {
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ if (intr & ONENAND_INT_MASTER)
+ break;
+ } else {
+ /* Timeout after 20ms */
+ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+ if (ctrl & ONENAND_CTRL_ONGO) {
+ /*
+ * The operation seems to be still going
+ * so give it some more time.
+ */
+ retry_cnt += 1;
+ if (retry_cnt < 3) {
+ timeout = jiffies +
+ msecs_to_jiffies(20);
+ continue;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ intr = read_reg(c, ONENAND_REG_INTERRUPT);
+ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+
+ if (intr & ONENAND_INT_READ) {
+ int ecc = read_reg(c, ONENAND_REG_ECC_STATUS);
+
+ if (ecc) {
+ unsigned int addr1, addr8;
+
+ addr1 = read_reg(c, ONENAND_REG_START_ADDRESS1);
+ addr8 = read_reg(c, ONENAND_REG_START_ADDRESS8);
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ printk(KERN_ERR "onenand_wait: ECC error = "
+ "0x%04x, addr1 %#x, addr8 %#x\n",
+ ecc, addr1, addr8);
+ mtd->ecc_stats.failed++;
+ return -EBADMSG;
+ } else if (ecc & ONENAND_ECC_1BIT_ALL) {
+ printk(KERN_NOTICE "onenand_wait: correctable "
+ "ECC error = 0x%04x, addr1 %#x, "
+ "addr8 %#x\n", ecc, addr1, addr8);
+ mtd->ecc_stats.corrected++;
+ }
+ }
+ } else if (state == FL_READING) {
+ wait_err("timeout", state, ctrl, intr);
+ return -EIO;
+ }
+
+ if (ctrl & ONENAND_CTRL_ERROR) {
+ wait_err("controller error", state, ctrl, intr);
+ if (ctrl & ONENAND_CTRL_LOCK)
+ printk(KERN_ERR "onenand_wait: "
+ "Device is write protected!!!\n");
+ return -EIO;
+ }
+
+ if (ctrl & 0xFE9F)
+ wait_warn("unexpected controller status", state, ctrl, intr);
+
+ return 0;
+}
+
+static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area)
+{
+ struct onenand_chip *this = mtd->priv;
+
+ if (ONENAND_CURRENT_BUFFERRAM(this)) {
+ if (area == ONENAND_DATARAM)
+ return mtd->writesize;
+ if (area == ONENAND_SPARERAM)
+ return mtd->oobsize;
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_ARCH_OMAP3) || defined(MULTI_OMAP2)
+
+static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+ unsigned long timeout;
+ void *buf = (void *)buffer;
+ size_t xtra;
+ volatile unsigned *done;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ if (bram_offset & 3 || (size_t)buf & 3 || count < 384)
+ goto out_copy;
+
+ if (buf >= high_memory) {
+ struct page *p1;
+
+ if (((size_t)buf & PAGE_MASK) !=
+ ((size_t)(buf + count - 1) & PAGE_MASK))
+ goto out_copy;
+ p1 = vmalloc_to_page(buf);
+ if (!p1)
+ goto out_copy;
+ buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK);
+ }
+
+ xtra = count & 3;
+ if (xtra) {
+ count -= xtra;
+ memcpy(buf + count, this->base + bram_offset + count, xtra);
+ }
+
+ dma_src = c->phys_base + bram_offset;
+ dma_dst = dma_map_single(&c->pdev->dev, buf, count, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+ dev_err(&c->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ goto out_copy;
+ }
+
+ omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+ count >> 2, 1, 0, 0, 0);
+ omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(c->dma_done);
+ omap_start_dma(c->dma_channel);
+
+ timeout = jiffies + msecs_to_jiffies(20);
+ done = &c->dma_done.done;
+ while (time_before(jiffies, timeout))
+ if (*done)
+ break;
+
+ dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);
+
+ if (!*done) {
+ dev_err(&c->pdev->dev, "timeout waiting for DMA\n");
+ goto out_copy;
+ }
+
+ return 0;
+
+out_copy:
+ memcpy(buf, this->base + bram_offset, count);
+ return 0;
+}
+
+static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+ unsigned long timeout;
+ void *buf = (void *)buffer;
+ volatile unsigned *done;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ if (bram_offset & 3 || (size_t)buf & 3 || count < 384)
+ goto out_copy;
+
+ /* panic_write() may be in an interrupt context */
+ if (in_interrupt())
+ goto out_copy;
+
+ if (buf >= high_memory) {
+ struct page *p1;
+
+ if (((size_t)buf & PAGE_MASK) !=
+ ((size_t)(buf + count - 1) & PAGE_MASK))
+ goto out_copy;
+ p1 = vmalloc_to_page(buf);
+ if (!p1)
+ goto out_copy;
+ buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK);
+ }
+
+ dma_src = dma_map_single(&c->pdev->dev, buf, count, DMA_TO_DEVICE);
+ dma_dst = c->phys_base + bram_offset;
+ if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+ dev_err(&c->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ return -1;
+ }
+
+ omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+ count >> 2, 1, 0, 0, 0);
+ omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(c->dma_done);
+ omap_start_dma(c->dma_channel);
+
+ timeout = jiffies + msecs_to_jiffies(20);
+ done = &c->dma_done.done;
+ while (time_before(jiffies, timeout))
+ if (*done)
+ break;
+
+ dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);
+
+ if (!*done) {
+ dev_err(&c->pdev->dev, "timeout waiting for DMA\n");
+ goto out_copy;
+ }
+
+ return 0;
+
+out_copy:
+ memcpy(this->base + bram_offset, buf, count);
+ return 0;
+}
+
+#else
+
+int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count);
+
+int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count);
+
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(MULTI_OMAP2)
+
+static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ /* DMA is not used. Revisit PM requirements before enabling it. */
+ if (1 || (c->dma_channel < 0) ||
+ ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) ||
+ (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) {
+ memcpy(buffer, (__force void *)(this->base + bram_offset),
+ count);
+ return 0;
+ }
+
+ dma_src = c->phys_base + bram_offset;
+ dma_dst = dma_map_single(&c->pdev->dev, buffer, count,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+ dev_err(&c->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ return -1;
+ }
+
+ omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+ count / 4, 1, 0, 0, 0);
+ omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(c->dma_done);
+ omap_start_dma(c->dma_channel);
+ wait_for_completion(&c->dma_done);
+
+ dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);
+
+ return 0;
+}
+
+static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count)
+{
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
+ dma_addr_t dma_src, dma_dst;
+ int bram_offset;
+
+ bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+ /* DMA is not used. Revisit PM requirements before enabling it. */
+ if (1 || (c->dma_channel < 0) ||
+ ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) ||
+ (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) {
+ memcpy((__force void *)(this->base + bram_offset), buffer,
+ count);
+ return 0;
+ }
+
+ dma_src = dma_map_single(&c->pdev->dev, (void *) buffer, count,
+ DMA_TO_DEVICE);
+ dma_dst = c->phys_base + bram_offset;
+ if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+ dev_err(&c->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n",
+ count);
+ return -1;
+ }
+
+ omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S16,
+ count / 2, 1, 0, 0, 0);
+ omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_src, 0, 0);
+ omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_dst, 0, 0);
+
+ INIT_COMPLETION(c->dma_done);
+ omap_start_dma(c->dma_channel);
+ wait_for_completion(&c->dma_done);
+
+ dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);
+
+ return 0;
+}
+
+#else
+
+int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count);
+
+int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count);
+
+#endif
+
+static struct platform_driver omap2_onenand_driver;
+
+static int __adjust_timing(struct device *dev, void *data)
+{
+ int ret = 0;
+ struct omap2_onenand *c;
+
+ c = dev_get_drvdata(dev);
+
+ BUG_ON(c->setup == NULL);
+
+ /* DMA is not in use so this is all that is needed */
+ /* Revisit for OMAP3! */
+ ret = c->setup(c->onenand.base, c->freq);
+
+ return ret;
+}
+
+int omap2_onenand_rephase(void)
+{
+ return driver_for_each_device(&omap2_onenand_driver.driver, NULL,
+ NULL, __adjust_timing);
+}
+
+static void __devexit omap2_onenand_shutdown(struct platform_device *pdev)
+{
+ struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
+
+ /* With certain content in the buffer RAM, the OMAP boot ROM code
+ * can recognize the flash chip incorrectly. Zero it out before
+ * soft reset.
+ */
+ memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
+}
+
+static int __devinit omap2_onenand_probe(struct platform_device *pdev)
+{
+ struct omap_onenand_platform_data *pdata;
+ struct omap2_onenand *c;
+ int r;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "platform data missing\n");
+ return -ENODEV;
+ }
+
+ c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL);
+ if (!c)
+ return -ENOMEM;
+
+ init_completion(&c->irq_done);
+ init_completion(&c->dma_done);
+ c->gpmc_cs = pdata->cs;
+ c->gpio_irq = pdata->gpio_irq;
+ c->dma_channel = pdata->dma_channel;
+ if (c->dma_channel < 0) {
+ /* if -1, don't use DMA */
+ c->gpio_irq = 0;
+ }
+
+ r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base);
+ if (r < 0) {
+ dev_err(&pdev->dev, "Cannot request GPMC CS\n");
+ goto err_kfree;
+ }
+
+ if (request_mem_region(c->phys_base, ONENAND_IO_SIZE,
+ pdev->dev.driver->name) == NULL) {
+ dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, "
+ "size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE);
+ r = -EBUSY;
+ goto err_free_cs;
+ }
+ c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE);
+ if (c->onenand.base == NULL) {
+ r = -ENOMEM;
+ goto err_release_mem_region;
+ }
+
+ if (pdata->onenand_setup != NULL) {
+ r = pdata->onenand_setup(c->onenand.base, c->freq);
+ if (r < 0) {
+ dev_err(&pdev->dev, "Onenand platform setup failed: "
+ "%d\n", r);
+ goto err_iounmap;
+ }
+ c->setup = pdata->onenand_setup;
+ }
+
+ if (c->gpio_irq) {
+ if ((r = omap_request_gpio(c->gpio_irq)) < 0) {
+ dev_err(&pdev->dev, "Failed to request GPIO%d for "
+ "OneNAND\n", c->gpio_irq);
+ goto err_iounmap;
+ }
+ omap_set_gpio_direction(c->gpio_irq, 1);
+
+ if ((r = request_irq(OMAP_GPIO_IRQ(c->gpio_irq),
+ omap2_onenand_interrupt, IRQF_TRIGGER_RISING,
+ pdev->dev.driver->name, c)) < 0)
+ goto err_release_gpio;
+ }
+
+ if (c->dma_channel >= 0) {
+ r = omap_request_dma(0, pdev->dev.driver->name,
+ omap2_onenand_dma_cb, (void *) c,
+ &c->dma_channel);
+ if (r == 0) {
+ omap_set_dma_write_mode(c->dma_channel,
+ OMAP_DMA_WRITE_NON_POSTED);
+ omap_set_dma_src_data_pack(c->dma_channel, 1);
+ omap_set_dma_src_burst_mode(c->dma_channel,
+ OMAP_DMA_DATA_BURST_8);
+ omap_set_dma_dest_data_pack(c->dma_channel, 1);
+ omap_set_dma_dest_burst_mode(c->dma_channel,
+ OMAP_DMA_DATA_BURST_8);
+ } else {
+ dev_info(&pdev->dev,
+ "failed to allocate DMA for OneNAND, "
+ "using PIO instead\n");
+ c->dma_channel = -1;
+ }
+ }
+
+ dev_info(&pdev->dev, "initializing on CS%d, phys base 0x%08lx, virtual "
+ "base %p\n", c->gpmc_cs, c->phys_base,
+ c->onenand.base);
+
+ c->pdev = pdev;
+ c->mtd.name = pdev->dev.bus_id;
+ c->mtd.priv = &c->onenand;
+ c->mtd.owner = THIS_MODULE;
+
+ if (c->dma_channel >= 0) {
+ struct onenand_chip *this = &c->onenand;
+
+ this->wait = omap2_onenand_wait;
+ if (cpu_is_omap34xx()) {
+ this->read_bufferram = omap3_onenand_read_bufferram;
+ this->write_bufferram = omap3_onenand_write_bufferram;
+ } else {
+ this->read_bufferram = omap2_onenand_read_bufferram;
+ this->write_bufferram = omap2_onenand_write_bufferram;
+ }
+ }
+
+ if ((r = onenand_scan(&c->mtd, 1)) < 0)
+ goto err_release_dma;
+
+ switch ((c->onenand.version_id >> 4) & 0xf) {
+ case 0:
+ c->freq = 40;
+ break;
+ case 1:
+ c->freq = 54;
+ break;
+ case 2:
+ c->freq = 66;
+ break;
+ case 3:
+ c->freq = 83;
+ break;
+ }
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (pdata->parts != NULL)
+ r = add_mtd_partitions(&c->mtd, pdata->parts,
+ pdata->nr_parts);
+ else
+#endif
+ r = add_mtd_device(&c->mtd);
+ if (r < 0)
+ goto err_release_onenand;
+
+ platform_set_drvdata(pdev, c);
+
+ return 0;
+
+err_release_onenand:
+ onenand_release(&c->mtd);
+err_release_dma:
+ if (c->dma_channel != -1)
+ omap_free_dma(c->dma_channel);
+ if (c->gpio_irq)
+ free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);
+err_release_gpio:
+ if (c->gpio_irq)
+ omap_free_gpio(c->gpio_irq);
+err_iounmap:
+ iounmap(c->onenand.base);
+err_release_mem_region:
+ release_mem_region(c->phys_base, ONENAND_IO_SIZE);
+err_free_cs:
+ gpmc_cs_free(c->gpmc_cs);
+err_kfree:
+ kfree(c);
+
+ return r;
+}
+
+static int __devexit omap2_onenand_remove(struct platform_device *pdev)
+{
+ struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
+
+ BUG_ON(c == NULL);
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (c->parts)
+ del_mtd_partitions(&c->mtd);
+ else
+ del_mtd_device(&c->mtd);
+#else
+ del_mtd_device(&c->mtd);
+#endif
+
+ onenand_release(&c->mtd);
+ if (c->dma_channel != -1)
+ omap_free_dma(c->dma_channel);
+ omap2_onenand_shutdown(pdev);
+ platform_set_drvdata(pdev, NULL);
+ if (c->gpio_irq) {
+ free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);
+ omap_free_gpio(c->gpio_irq);
+ }
+ iounmap(c->onenand.base);
+ release_mem_region(c->phys_base, ONENAND_IO_SIZE);
+ kfree(c);
+
+ return 0;
+}
+
+static struct platform_driver omap2_onenand_driver = {
+ .probe = omap2_onenand_probe,
+ .remove = omap2_onenand_remove,
+ .shutdown = omap2_onenand_shutdown,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap2_onenand_init(void)
+{
+ printk(KERN_INFO "OneNAND driver initializing\n");
+ return platform_driver_register(&omap2_onenand_driver);
+}
+
+static void __exit omap2_onenand_exit(void)
+{
+ platform_driver_unregister(&omap2_onenand_driver);
+}
+
+module_init(omap2_onenand_init);
+module_exit(omap2_onenand_exit);
+
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>");
+MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3");
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 926cf3a4135..90ed319f26e 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1794,7 +1794,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
return -EINVAL;
}
- instr->fail_addr = 0xffffffff;
+ instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_ERASING);
diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c
index a5f3d60047d..33a5d6ed6f1 100644
--- a/drivers/mtd/ssfdc.c
+++ b/drivers/mtd/ssfdc.c
@@ -321,8 +321,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
DEBUG(MTD_DEBUG_LEVEL1,
"SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",
ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len,
- (ssfdc->map_len + MAX_PHYS_BLK_PER_ZONE - 1) /
- MAX_PHYS_BLK_PER_ZONE);
+ DIV_ROUND_UP(ssfdc->map_len, MAX_PHYS_BLK_PER_ZONE));
/* Set geometry */
ssfdc->heads = 16;
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 03c759b4eeb..b30a0b83d7f 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -104,12 +104,9 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
struct ubi_volume_desc *desc;
int vol_id = iminor(inode) - 1, mode, ubi_num;
- lock_kernel();
ubi_num = ubi_major2num(imajor(inode));
- if (ubi_num < 0) {
- unlock_kernel();
+ if (ubi_num < 0)
return ubi_num;
- }
if (file->f_mode & FMODE_WRITE)
mode = UBI_READWRITE;
@@ -119,7 +116,6 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
dbg_gen("open volume %d, mode %d", vol_id, mode);
desc = ubi_open_volume(ubi_num, vol_id, mode);
- unlock_kernel();
if (IS_ERR(desc))
return PTR_ERR(desc);
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 967bb4406df..4f2daa5bbec 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -387,7 +387,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
pnum, vol_id, lnum, ec, sqnum, bitflips);
sv = add_volume(si, vol_id, pnum, vid_hdr);
- if (IS_ERR(sv) < 0)
+ if (IS_ERR(sv))
return PTR_ERR(sv);
if (si->max_sqnum < sqnum)
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 217d0e111b2..333c8941552 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -244,8 +244,8 @@ static int vtbl_check(const struct ubi_device *ubi,
}
if (reserved_pebs > ubi->good_peb_count) {
- dbg_err("too large reserved_pebs, good PEBs %d",
- ubi->good_peb_count);
+ dbg_err("too large reserved_pebs %d, good PEBs %d",
+ reserved_pebs, ubi->good_peb_count);
err = 9;
goto bad;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 491ee16da5c..9ba295d9dd9 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -90,7 +90,7 @@ static int vortex_debug = 1;
#include <linux/eisa.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <asm/irq.h> /* For NR_IRQS only. */
+#include <asm/irq.h> /* For nr_irqs only. */
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -1221,7 +1221,7 @@ static int __devinit vortex_probe1(struct device *gendev,
if (print_info)
printk(", IRQ %d\n", dev->irq);
/* Tell them about an invalid IRQ. */
- if (dev->irq <= 0 || dev->irq >= NR_IRQS)
+ if (dev->irq <= 0 || dev->irq >= nr_irqs)
printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
dev->irq);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ad301ace608..0b71ebc074b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -464,6 +464,12 @@ config MIPS_JAZZ_SONIC
This is the driver for the onboard card of MIPS Magnum 4000,
Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
+config XTENSA_XT2000_SONIC
+ tristate "Xtensa XT2000 onboard SONIC Ethernet support"
+ depends on XTENSA_PLATFORM_XT2000
+ help
+ This is the driver for the onboard card of the Xtensa XT2000 board.
+
config MIPS_AU1X00_ENET
bool "MIPS AU1000 Ethernet support"
depends on SOC_AU1X00
@@ -2504,6 +2510,15 @@ config PASEMI_MAC
This driver supports the on-chip 1/10Gbit Ethernet controller on
PA Semi's PWRficient line of chips.
+config MLX4_EN
+ tristate "Mellanox Technologies 10Gbit Ethernet support"
+ depends on PCI && INET
+ select MLX4_CORE
+ select INET_LRO
+ help
+ This driver supports Mellanox Technologies ConnectX Ethernet
+ devices.
+
config MLX4_CORE
tristate
depends on PCI
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index fa2510b2e60..f19acf8b922 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -227,6 +227,8 @@ pasemi_mac_driver-objs := pasemi_mac.o pasemi_mac_ethtool.o
obj-$(CONFIG_MLX4_CORE) += mlx4/
obj-$(CONFIG_ENC28J60) += enc28j60.o
+obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
+
obj-$(CONFIG_MACB) += macb.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index 08e18bcb970..45dd9bdc5d6 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -2,6 +2,7 @@
* Driver for the MPC5200 Fast Ethernet Controller - MDIO bus driver
*
* Copyright (C) 2007 Domen Puncer, Telargo, Inc.
+ * Copyright (C) 2008 Wolfram Sang, Pengutronix
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
@@ -21,58 +22,45 @@ struct mpc52xx_fec_mdio_priv {
struct mpc52xx_fec __iomem *regs;
};
-static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id,
+ int reg, u32 value)
{
struct mpc52xx_fec_mdio_priv *priv = bus->priv;
struct mpc52xx_fec __iomem *fec;
int tries = 100;
- u32 request = FEC_MII_READ_FRAME;
+
+ value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+ value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
fec = priv->regs;
out_be32(&fec->ievent, FEC_IEVENT_MII);
-
- request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
- request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
-
- out_be32(&priv->regs->mii_data, request);
+ out_be32(&priv->regs->mii_data, value);
/* wait for it to finish, this takes about 23 us on lite5200b */
while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
udelay(5);
- if (tries == 0)
+ if (!tries)
return -ETIMEDOUT;
- return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK;
+ return value & FEC_MII_DATA_OP_RD ?
+ in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK : 0;
}
-static int mpc52xx_fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
+static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
{
- struct mpc52xx_fec_mdio_priv *priv = bus->priv;
- struct mpc52xx_fec __iomem *fec;
- u32 value = data;
- int tries = 100;
-
- fec = priv->regs;
- out_be32(&fec->ievent, FEC_IEVENT_MII);
-
- value |= FEC_MII_WRITE_FRAME;
- value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
- value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
-
- out_be32(&priv->regs->mii_data, value);
-
- /* wait for request to finish */
- while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
- udelay(5);
-
- if (tries == 0)
- return -ETIMEDOUT;
+ return mpc52xx_fec_mdio_transfer(bus, phy_id, reg, FEC_MII_READ_FRAME);
+}
- return 0;
+static int mpc52xx_fec_mdio_write(struct mii_bus *bus, int phy_id, int reg,
+ u16 data)
+{
+ return mpc52xx_fec_mdio_transfer(bus, phy_id, reg,
+ data | FEC_MII_WRITE_FRAME);
}
-static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
+static int mpc52xx_fec_mdio_probe(struct of_device *of,
+ const struct of_device_id *match)
{
struct device *dev = &of->dev;
struct device_node *np = of->node;
@@ -131,7 +119,8 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i
dev_set_drvdata(dev, bus);
/* set MII speed */
- out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
+ out_be32(&priv->regs->mii_speed,
+ ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
/* enable MII interrupt */
out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII);
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 17ac6975d70..b6a816e60c0 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -416,10 +416,10 @@ static int ser12_open(struct net_device *dev)
if (!dev || !bc)
return -ENXIO;
if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT ||
- dev->irq < 2 || dev->irq > NR_IRQS) {
+ dev->irq < 2 || dev->irq > nr_irqs) {
printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) "
"or irq (2 <= irq <= %d)\n",
- 0xffff-SER12_EXTENT, NR_IRQS);
+ 0xffff-SER12_EXTENT, nr_irqs);
return -ENXIO;
}
if (bc->baud < 300 || bc->baud > 4800) {
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 45ae9d1191d..c17e39bc546 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1465,7 +1465,7 @@ static void z8530_init(void)
printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2);
flag=" ";
- for (k = 0; k < NR_IRQS; k++)
+ for (k = 0; k < nr_irqs; k++)
if (Ivec[k].used)
{
printk("%s%d", flag, k);
@@ -1728,7 +1728,7 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (hwcfg.irq == 2) hwcfg.irq = 9;
- if (hwcfg.irq < 0 || hwcfg.irq >= NR_IRQS)
+ if (hwcfg.irq < 0 || hwcfg.irq >= nr_irqs)
return -EINVAL;
if (!Ivec[hwcfg.irq].used && hwcfg.irq)
@@ -2148,7 +2148,7 @@ static void __exit scc_cleanup_driver(void)
}
/* To unload the port must be closed so no real IRQ pending */
- for (k=0; k < NR_IRQS ; k++)
+ for (k = 0; k < nr_irqs ; k++)
if (Ivec[k].used) free_irq(k, NULL);
local_irq_enable();
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index efcf21c9f5c..2ee2622258f 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -2604,8 +2604,16 @@ static int __devinit emac_init_config(struct emac_instance *dev)
if (of_device_is_compatible(np, "ibm,emac-440ep") ||
of_device_is_compatible(np, "ibm,emac-440gr"))
dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX;
- if (of_device_is_compatible(np, "ibm,emac-405ez"))
+ if (of_device_is_compatible(np, "ibm,emac-405ez")) {
+#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CONTROL
dev->features |= EMAC_FTR_NO_FLOW_CONTROL_40x;
+#else
+ printk(KERN_ERR "%s: Flow control not disabled!\n",
+ np->full_name);
+ return -ENXIO;
+#endif
+ }
+
}
/* Fixup some feature bits based on the device tree */
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
index 1839d3f154a..ecf9798987f 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ibm_newemac/mal.c
@@ -280,9 +280,11 @@ static irqreturn_t mal_txeob(int irq, void *dev_instance)
mal_schedule_poll(mal);
set_mal_dcrn(mal, MAL_TXEOBISR, r);
+#ifdef CONFIG_PPC_DCR_NATIVE
if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))
mtdcri(SDR0, DCRN_SDR_ICINTSTAT,
(mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICTX));
+#endif
return IRQ_HANDLED;
}
@@ -298,9 +300,11 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance)
mal_schedule_poll(mal);
set_mal_dcrn(mal, MAL_RXEOBISR, r);
+#ifdef CONFIG_PPC_DCR_NATIVE
if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))
mtdcri(SDR0, DCRN_SDR_ICINTSTAT,
(mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICRX));
+#endif
return IRQ_HANDLED;
}
@@ -572,9 +576,18 @@ static int __devinit mal_probe(struct of_device *ofdev,
goto fail;
}
- if (of_device_is_compatible(ofdev->node, "ibm,mcmal-405ez"))
+ if (of_device_is_compatible(ofdev->node, "ibm,mcmal-405ez")) {
+#if defined(CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT) && \
+ defined(CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR)
mal->features |= (MAL_FTR_CLEAR_ICINTSTAT |
MAL_FTR_COMMON_ERR_INT);
+#else
+ printk(KERN_ERR "%s: Support for 405EZ not enabled!\n",
+ ofdev->node->full_name);
+ err = -ENODEV;
+ goto fail;
+#endif
+ }
mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0);
mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1);
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index 73fe83be34f..e1429fc6d05 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -540,7 +540,8 @@ static int kingsun_probe(struct usb_interface *intf,
if (ret != 0)
goto free_mem;
- info("IrDA: Registered KingSun/DonShine device %s", net->name);
+ dev_info(&net->dev, "IrDA: Registered KingSun/DonShine device %s\n",
+ net->name);
usb_set_intfdata(intf, kingsun);
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index 8c257a51341..2482d61662a 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -801,7 +801,8 @@ static int ks959_probe(struct usb_interface *intf,
if (ret != 0)
goto free_mem;
- info("IrDA: Registered KingSun KS-959 device %s", net->name);
+ dev_info(&net->dev, "IrDA: Registered KingSun KS-959 device %s\n",
+ net->name);
usb_set_intfdata(intf, kingsun);
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
index d01a28593ce..1e0de93fd61 100644
--- a/drivers/net/irda/ksdazzle-sir.c
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -705,7 +705,8 @@ static int ksdazzle_probe(struct usb_interface *intf,
if (ret != 0)
goto free_mem;
- info("IrDA: Registered KingSun/Dazzle device %s", net->name);
+ dev_info(&net->dev, "IrDA: Registered KingSun/Dazzle device %s\n",
+ net->name);
usb_set_intfdata(intf, kingsun);
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 05196378274..3575804fd7c 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -506,7 +506,7 @@ static int change_speed(struct stir_cb *stir, unsigned speed)
goto found;
}
- warn("%s: invalid speed %d", stir->netdev->name, speed);
+ dev_warn(&stir->netdev->dev, "invalid speed %d\n", speed);
return -EINVAL;
found:
@@ -598,8 +598,8 @@ static int fifo_txwait(struct stir_cb *stir, int space)
err = read_reg(stir, REG_FIFOCTL, stir->fifo_status,
FIFO_REGS_SIZE);
if (unlikely(err != FIFO_REGS_SIZE)) {
- warn("%s: FIFO register read error: %d",
- stir->netdev->name, err);
+ dev_warn(&stir->netdev->dev,
+ "FIFO register read error: %d\n", err);
return err;
}
@@ -783,8 +783,9 @@ static int stir_transmit_thread(void *arg)
if (unlikely(receive_start(stir))) {
if (net_ratelimit())
- info("%s: receive usb submit failed",
- stir->netdev->name);
+ dev_info(&dev->dev,
+ "%s: receive usb submit failed\n",
+ stir->netdev->name);
stir->receiving = 0;
msleep(10);
continue;
@@ -836,8 +837,8 @@ static void stir_rcv_irq(struct urb *urb)
/* in case of error, the kernel thread will restart us */
if (err) {
- warn("%s: usb receive submit error: %d",
- stir->netdev->name, err);
+ dev_warn(&stir->netdev->dev, "usb receive submit error: %d\n",
+ err);
stir->receiving = 0;
wake_up_process(stir->thread);
}
@@ -1073,7 +1074,8 @@ static int stir_probe(struct usb_interface *intf,
if (ret != 0)
goto err_out2;
- info("IrDA: Registered SigmaTel device %s", net->name);
+ dev_info(&intf->dev, "IrDA: Registered SigmaTel device %s\n",
+ net->name);
usb_set_intfdata(intf, stir);
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 0952a6528f5..a7a97bf998f 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -1,4 +1,9 @@
obj-$(CONFIG_MLX4_CORE) += mlx4_core.o
mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
- mr.o pd.o profile.o qp.o reset.o srq.o
+ mr.o pd.o port.o profile.o qp.o reset.o srq.o
+
+obj-$(CONFIG_MLX4_EN) += mlx4_en.o
+
+mlx4_en-y := en_main.o en_tx.o en_rx.o en_params.o en_port.o en_cq.o \
+ en_resources.o en_netdev.o
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c
index b411b79d72a..ad95d5f7b63 100644
--- a/drivers/net/mlx4/alloc.c
+++ b/drivers/net/mlx4/alloc.c
@@ -48,13 +48,16 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap)
obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last);
if (obj >= bitmap->max) {
- bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
+ bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
+ & bitmap->mask;
obj = find_first_zero_bit(bitmap->table, bitmap->max);
}
if (obj < bitmap->max) {
set_bit(obj, bitmap->table);
- bitmap->last = (obj + 1) & (bitmap->max - 1);
+ bitmap->last = (obj + 1);
+ if (bitmap->last == bitmap->max)
+ bitmap->last = 0;
obj |= bitmap->top;
} else
obj = -1;
@@ -66,16 +69,90 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap)
void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj)
{
- obj &= bitmap->max - 1;
+ mlx4_bitmap_free_range(bitmap, obj, 1);
+}
+
+static unsigned long find_aligned_range(unsigned long *bitmap,
+ u32 start, u32 nbits,
+ int len, int align)
+{
+ unsigned long end, i;
+
+again:
+ start = ALIGN(start, align);
+
+ while ((start < nbits) && test_bit(start, bitmap))
+ start += align;
+
+ if (start >= nbits)
+ return -1;
+
+ end = start+len;
+ if (end > nbits)
+ return -1;
+
+ for (i = start + 1; i < end; i++) {
+ if (test_bit(i, bitmap)) {
+ start = i + 1;
+ goto again;
+ }
+ }
+
+ return start;
+}
+
+u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
+{
+ u32 obj, i;
+
+ if (likely(cnt == 1 && align == 1))
+ return mlx4_bitmap_alloc(bitmap);
+
+ spin_lock(&bitmap->lock);
+
+ obj = find_aligned_range(bitmap->table, bitmap->last,
+ bitmap->max, cnt, align);
+ if (obj >= bitmap->max) {
+ bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
+ & bitmap->mask;
+ obj = find_aligned_range(bitmap->table, 0, bitmap->max,
+ cnt, align);
+ }
+
+ if (obj < bitmap->max) {
+ for (i = 0; i < cnt; i++)
+ set_bit(obj + i, bitmap->table);
+ if (obj == bitmap->last) {
+ bitmap->last = (obj + cnt);
+ if (bitmap->last >= bitmap->max)
+ bitmap->last = 0;
+ }
+ obj |= bitmap->top;
+ } else
+ obj = -1;
+
+ spin_unlock(&bitmap->lock);
+
+ return obj;
+}
+
+void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
+{
+ u32 i;
+
+ obj &= bitmap->max + bitmap->reserved_top - 1;
spin_lock(&bitmap->lock);
- clear_bit(obj, bitmap->table);
+ for (i = 0; i < cnt; i++)
+ clear_bit(obj + i, bitmap->table);
bitmap->last = min(bitmap->last, obj);
- bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
+ bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
+ & bitmap->mask;
spin_unlock(&bitmap->lock);
}
-int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved)
+int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
+ u32 reserved_bot, u32 reserved_top)
{
int i;
@@ -85,14 +162,16 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved
bitmap->last = 0;
bitmap->top = 0;
- bitmap->max = num;
+ bitmap->max = num - reserved_top;
bitmap->mask = mask;
+ bitmap->reserved_top = reserved_top;
spin_lock_init(&bitmap->lock);
- bitmap->table = kzalloc(BITS_TO_LONGS(num) * sizeof (long), GFP_KERNEL);
+ bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) *
+ sizeof (long), GFP_KERNEL);
if (!bitmap->table)
return -ENOMEM;
- for (i = 0; i < reserved; ++i)
+ for (i = 0; i < reserved_bot; ++i)
set_bit(i, bitmap->table);
return 0;
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index 9bb50e3f897..b7ad2829d67 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -300,7 +300,7 @@ int mlx4_init_cq_table(struct mlx4_dev *dev)
INIT_RADIX_TREE(&cq_table->tree, GFP_ATOMIC);
err = mlx4_bitmap_init(&cq_table->bitmap, dev->caps.num_cqs,
- dev->caps.num_cqs - 1, dev->caps.reserved_cqs);
+ dev->caps.num_cqs - 1, dev->caps.reserved_cqs, 0);
if (err)
return err;
diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c
new file mode 100644
index 00000000000..1368a8010af
--- /dev/null
+++ b/drivers/net/mlx4/en_cq.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/mlx4/cq.h>
+#include <linux/mlx4/qp.h>
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4_en.h"
+
+static void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event)
+{
+ return;
+}
+
+
+int mlx4_en_create_cq(struct mlx4_en_priv *priv,
+ struct mlx4_en_cq *cq,
+ int entries, int ring, enum cq_type mode)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ cq->size = entries;
+ if (mode == RX)
+ cq->buf_size = cq->size * sizeof(struct mlx4_cqe);
+ else
+ cq->buf_size = sizeof(struct mlx4_cqe);
+
+ cq->ring = ring;
+ cq->is_tx = mode;
+ spin_lock_init(&cq->lock);
+
+ err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres,
+ cq->buf_size, 2 * PAGE_SIZE);
+ if (err)
+ return err;
+
+ err = mlx4_en_map_buffer(&cq->wqres.buf);
+ if (err)
+ mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
+
+ return err;
+}
+
+int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ cq->dev = mdev->pndev[priv->port];
+ cq->mcq.set_ci_db = cq->wqres.db.db;
+ cq->mcq.arm_db = cq->wqres.db.db + 1;
+ *cq->mcq.set_ci_db = 0;
+ *cq->mcq.arm_db = 0;
+ cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf;
+ memset(cq->buf, 0, cq->buf_size);
+
+ err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar,
+ cq->wqres.db.dma, &cq->mcq, cq->is_tx);
+ if (err)
+ return err;
+
+ cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq;
+ cq->mcq.event = mlx4_en_cq_event;
+
+ if (cq->is_tx) {
+ init_timer(&cq->timer);
+ cq->timer.function = mlx4_en_poll_tx_cq;
+ cq->timer.data = (unsigned long) cq;
+ } else {
+ netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64);
+ napi_enable(&cq->napi);
+ }
+
+ return 0;
+}
+
+void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ mlx4_en_unmap_buffer(&cq->wqres.buf);
+ mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
+ cq->buf_size = 0;
+ cq->buf = NULL;
+}
+
+void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ if (cq->is_tx)
+ del_timer(&cq->timer);
+ else
+ napi_disable(&cq->napi);
+
+ mlx4_cq_free(mdev->dev, &cq->mcq);
+}
+
+/* Set rx cq moderation parameters */
+int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
+{
+ return mlx4_cq_modify(priv->mdev->dev, &cq->mcq,
+ cq->moder_cnt, cq->moder_time);
+}
+
+int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
+{
+ cq->armed = 1;
+ mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map,
+ &priv->mdev->uar_lock);
+
+ return 0;
+}
+
+
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c
new file mode 100644
index 00000000000..1b0eebf84f7
--- /dev/null
+++ b/drivers/net/mlx4/en_main.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/cpumask.h>
+
+#include <linux/mlx4/driver.h>
+#include <linux/mlx4/device.h>
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4_en.h"
+
+MODULE_AUTHOR("Liran Liss, Yevgeny Petrilin");
+MODULE_DESCRIPTION("Mellanox ConnectX HCA Ethernet driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION " ("DRV_RELDATE")");
+
+static const char mlx4_en_version[] =
+ DRV_NAME ": Mellanox ConnectX HCA Ethernet driver v"
+ DRV_VERSION " (" DRV_RELDATE ")\n";
+
+static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
+ enum mlx4_dev_event event, int port)
+{
+ struct mlx4_en_dev *mdev = (struct mlx4_en_dev *) endev_ptr;
+ struct mlx4_en_priv *priv;
+
+ if (!mdev->pndev[port])
+ return;
+
+ priv = netdev_priv(mdev->pndev[port]);
+ switch (event) {
+ case MLX4_DEV_EVENT_PORT_UP:
+ case MLX4_DEV_EVENT_PORT_DOWN:
+ /* To prevent races, we poll the link state in a separate
+ task rather than changing it here */
+ priv->link_state = event;
+ queue_work(mdev->workqueue, &priv->linkstate_task);
+ break;
+
+ case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
+ mlx4_err(mdev, "Internal error detected, restarting device\n");
+ break;
+
+ default:
+ mlx4_warn(mdev, "Unhandled event: %d\n", event);
+ }
+}
+
+static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
+{
+ struct mlx4_en_dev *mdev = endev_ptr;
+ int i;
+
+ mutex_lock(&mdev->state_lock);
+ mdev->device_up = false;
+ mutex_unlock(&mdev->state_lock);
+
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
+ if (mdev->pndev[i])
+ mlx4_en_destroy_netdev(mdev->pndev[i]);
+
+ flush_workqueue(mdev->workqueue);
+ destroy_workqueue(mdev->workqueue);
+ mlx4_mr_free(dev, &mdev->mr);
+ mlx4_uar_free(dev, &mdev->priv_uar);
+ mlx4_pd_free(dev, mdev->priv_pdn);
+ kfree(mdev);
+}
+
+static void *mlx4_en_add(struct mlx4_dev *dev)
+{
+ static int mlx4_en_version_printed;
+ struct mlx4_en_dev *mdev;
+ int i;
+ int err;
+
+ if (!mlx4_en_version_printed) {
+ printk(KERN_INFO "%s", mlx4_en_version);
+ mlx4_en_version_printed++;
+ }
+
+ mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+ if (!mdev) {
+ dev_err(&dev->pdev->dev, "Device struct alloc failed, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_free_res;
+ }
+
+ if (mlx4_pd_alloc(dev, &mdev->priv_pdn))
+ goto err_free_dev;
+
+ if (mlx4_uar_alloc(dev, &mdev->priv_uar))
+ goto err_pd;
+
+ mdev->uar_map = ioremap(mdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
+ if (!mdev->uar_map)
+ goto err_uar;
+ spin_lock_init(&mdev->uar_lock);
+
+ mdev->dev = dev;
+ mdev->dma_device = &(dev->pdev->dev);
+ mdev->pdev = dev->pdev;
+ mdev->device_up = false;
+
+ mdev->LSO_support = !!(dev->caps.flags & (1 << 15));
+ if (!mdev->LSO_support)
+ mlx4_warn(mdev, "LSO not supported, please upgrade to later "
+ "FW version to enable LSO\n");
+
+ if (mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull,
+ MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ,
+ 0, 0, &mdev->mr)) {
+ mlx4_err(mdev, "Failed allocating memory region\n");
+ goto err_uar;
+ }
+ if (mlx4_mr_enable(mdev->dev, &mdev->mr)) {
+ mlx4_err(mdev, "Failed enabling memory region\n");
+ goto err_mr;
+ }
+
+ /* Build device profile according to supplied module parameters */
+ err = mlx4_en_get_profile(mdev);
+ if (err) {
+ mlx4_err(mdev, "Bad module parameters, aborting.\n");
+ goto err_mr;
+ }
+
+ /* Configure wich ports to start according to module parameters */
+ mdev->port_cnt = 0;
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
+ mdev->port_cnt++;
+
+ /* If we did not receive an explicit number of Rx rings, default to
+ * the number of completion vectors populated by the mlx4_core */
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
+ mlx4_info(mdev, "Using %d tx rings for port:%d\n",
+ mdev->profile.prof[i].tx_ring_num, i);
+ if (!mdev->profile.prof[i].rx_ring_num) {
+ mdev->profile.prof[i].rx_ring_num = 1;
+ mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n",
+ 1, i);
+ } else
+ mlx4_info(mdev, "Using %d rx rings for port:%d\n",
+ mdev->profile.prof[i].rx_ring_num, i);
+ }
+
+ /* Create our own workqueue for reset/multicast tasks
+ * Note: we cannot use the shared workqueue because of deadlocks caused
+ * by the rtnl lock */
+ mdev->workqueue = create_singlethread_workqueue("mlx4_en");
+ if (!mdev->workqueue) {
+ err = -ENOMEM;
+ goto err_close_nic;
+ }
+
+ /* At this stage all non-port specific tasks are complete:
+ * mark the card state as up */
+ mutex_init(&mdev->state_lock);
+ mdev->device_up = true;
+
+ /* Setup ports */
+
+ /* Create a netdev for each port */
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
+ mlx4_info(mdev, "Activating port:%d\n", i);
+ if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) {
+ mdev->pndev[i] = NULL;
+ goto err_free_netdev;
+ }
+ }
+ return mdev;
+
+
+err_free_netdev:
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
+ if (mdev->pndev[i])
+ mlx4_en_destroy_netdev(mdev->pndev[i]);
+ }
+
+ mutex_lock(&mdev->state_lock);
+ mdev->device_up = false;
+ mutex_unlock(&mdev->state_lock);
+ flush_workqueue(mdev->workqueue);
+
+ /* Stop event queue before we drop down to release shared SW state */
+
+err_close_nic:
+ destroy_workqueue(mdev->workqueue);
+err_mr:
+ mlx4_mr_free(dev, &mdev->mr);
+err_uar:
+ mlx4_uar_free(dev, &mdev->priv_uar);
+err_pd:
+ mlx4_pd_free(dev, mdev->priv_pdn);
+err_free_dev:
+ kfree(mdev);
+err_free_res:
+ return NULL;
+}
+
+static struct mlx4_interface mlx4_en_interface = {
+ .add = mlx4_en_add,
+ .remove = mlx4_en_remove,
+ .event = mlx4_en_event,
+};
+
+static int __init mlx4_en_init(void)
+{
+ return mlx4_register_interface(&mlx4_en_interface);
+}
+
+static void __exit mlx4_en_cleanup(void)
+{
+ mlx4_unregister_interface(&mlx4_en_interface);
+}
+
+module_init(mlx4_en_init);
+module_exit(mlx4_en_cleanup);
+
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
new file mode 100644
index 00000000000..a339afbeed3
--- /dev/null
+++ b/drivers/net/mlx4/en_netdev.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/tcp.h>
+#include <linux/if_vlan.h>
+#include <linux/delay.h>
+
+#include <linux/mlx4/driver.h>
+#include <linux/mlx4/device.h>
+#include <linux/mlx4/cmd.h>
+#include <linux/mlx4/cq.h>
+
+#include "mlx4_en.h"
+#include "en_port.h"
+
+
+static void mlx4_en_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ mlx4_dbg(HW, priv, "Registering VLAN group:%p\n", grp);
+ priv->vlgrp = grp;
+
+ mutex_lock(&mdev->state_lock);
+ if (mdev->device_up && priv->port_up) {
+ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, grp);
+ if (err)
+ mlx4_err(mdev, "Failed configuring VLAN filter\n");
+ }
+ mutex_unlock(&mdev->state_lock);
+}
+
+static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ if (!priv->vlgrp)
+ return;
+
+ mlx4_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n",
+ vid, vlan_group_get_device(priv->vlgrp, vid));
+
+ /* Add VID to port VLAN filter */
+ mutex_lock(&mdev->state_lock);
+ if (mdev->device_up && priv->port_up) {
+ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
+ if (err)
+ mlx4_err(mdev, "Failed configuring VLAN filter\n");
+ }
+ mutex_unlock(&mdev->state_lock);
+}
+
+static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ if (!priv->vlgrp)
+ return;
+
+ mlx4_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp "
+ "entry:%p)\n", vid, priv->vlgrp,
+ vlan_group_get_device(priv->vlgrp, vid));
+ vlan_group_set_device(priv->vlgrp, vid, NULL);
+
+ /* Remove VID from port VLAN filter */
+ mutex_lock(&mdev->state_lock);
+ if (mdev->device_up && priv->port_up) {
+ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
+ if (err)
+ mlx4_err(mdev, "Failed configuring VLAN filter\n");
+ }
+ mutex_unlock(&mdev->state_lock);
+}
+
+static u64 mlx4_en_mac_to_u64(u8 *addr)
+{
+ u64 mac = 0;
+ int i;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ mac <<= 8;
+ mac |= addr[i];
+ }
+ return mac;
+}
+
+static int mlx4_en_set_mac(struct net_device *dev, void *addr)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct sockaddr *saddr = addr;
+
+ if (!is_valid_ether_addr(saddr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
+ priv->mac = mlx4_en_mac_to_u64(dev->dev_addr);
+ queue_work(mdev->workqueue, &priv->mac_task);
+ return 0;
+}
+
+static void mlx4_en_do_set_mac(struct work_struct *work)
+{
+ struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+ mac_task);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err = 0;
+
+ mutex_lock(&mdev->state_lock);
+ if (priv->port_up) {
+ /* Remove old MAC and insert the new one */
+ mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index);
+ err = mlx4_register_mac(mdev->dev, priv->port,
+ priv->mac, &priv->mac_index);
+ if (err)
+ mlx4_err(mdev, "Failed changing HW MAC address\n");
+ } else
+ mlx4_dbg(HW, priv, "Port is down, exiting...\n");
+
+ mutex_unlock(&mdev->state_lock);
+}
+
+static void mlx4_en_clear_list(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct dev_mc_list *plist = priv->mc_list;
+ struct dev_mc_list *next;
+
+ while (plist) {
+ next = plist->next;
+ kfree(plist);
+ plist = next;
+ }
+ priv->mc_list = NULL;
+}
+
+static void mlx4_en_cache_mclist(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct dev_mc_list *mclist;
+ struct dev_mc_list *tmp;
+ struct dev_mc_list *plist = NULL;
+
+ for (mclist = dev->mc_list; mclist; mclist = mclist->next) {
+ tmp = kmalloc(sizeof(struct dev_mc_list), GFP_ATOMIC);
+ if (!tmp) {
+ mlx4_err(mdev, "failed to allocate multicast list\n");
+ mlx4_en_clear_list(dev);
+ return;
+ }
+ memcpy(tmp, mclist, sizeof(struct dev_mc_list));
+ tmp->next = NULL;
+ if (plist)
+ plist->next = tmp;
+ else
+ priv->mc_list = tmp;
+ plist = tmp;
+ }
+}
+
+
+static void mlx4_en_set_multicast(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+
+ if (!priv->port_up)
+ return;
+
+ queue_work(priv->mdev->workqueue, &priv->mcast_task);
+}
+
+static void mlx4_en_do_set_multicast(struct work_struct *work)
+{
+ struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+ mcast_task);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct net_device *dev = priv->dev;
+ struct dev_mc_list *mclist;
+ u64 mcast_addr = 0;
+ int err;
+
+ mutex_lock(&mdev->state_lock);
+ if (!mdev->device_up) {
+ mlx4_dbg(HW, priv, "Card is not up, ignoring "
+ "multicast change.\n");
+ goto out;
+ }
+ if (!priv->port_up) {
+ mlx4_dbg(HW, priv, "Port is down, ignoring "
+ "multicast change.\n");
+ goto out;
+ }
+
+ /*
+ * Promsicuous mode: disable all filters
+ */
+
+ if (dev->flags & IFF_PROMISC) {
+ if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) {
+ if (netif_msg_rx_status(priv))
+ mlx4_warn(mdev, "Port:%d entering promiscuous mode\n",
+ priv->port);
+ priv->flags |= MLX4_EN_FLAG_PROMISC;
+
+ /* Enable promiscouos mode */
+ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port,
+ priv->base_qpn, 1);
+ if (err)
+ mlx4_err(mdev, "Failed enabling "
+ "promiscous mode\n");
+
+ /* Disable port multicast filter (unconditionally) */
+ err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
+ 0, MLX4_MCAST_DISABLE);
+ if (err)
+ mlx4_err(mdev, "Failed disabling "
+ "multicast filter\n");
+
+ /* Disable port VLAN filter */
+ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL);
+ if (err)
+ mlx4_err(mdev, "Failed disabling "
+ "VLAN filter\n");
+ }
+ goto out;
+ }
+
+ /*
+ * Not in promiscous mode
+ */
+
+ if (priv->flags & MLX4_EN_FLAG_PROMISC) {
+ if (netif_msg_rx_status(priv))
+ mlx4_warn(mdev, "Port:%d leaving promiscuous mode\n",
+ priv->port);
+ priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+
+ /* Disable promiscouos mode */
+ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port,
+ priv->base_qpn, 0);
+ if (err)
+ mlx4_err(mdev, "Failed disabling promiscous mode\n");
+
+ /* Enable port VLAN filter */
+ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
+ if (err)
+ mlx4_err(mdev, "Failed enabling VLAN filter\n");
+ }
+
+ /* Enable/disable the multicast filter according to IFF_ALLMULTI */
+ if (dev->flags & IFF_ALLMULTI) {
+ err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
+ 0, MLX4_MCAST_DISABLE);
+ if (err)
+ mlx4_err(mdev, "Failed disabling multicast filter\n");
+ } else {
+ err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
+ 0, MLX4_MCAST_DISABLE);
+ if (err)
+ mlx4_err(mdev, "Failed disabling multicast filter\n");
+
+ /* Flush mcast filter and init it with broadcast address */
+ mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST,
+ 1, MLX4_MCAST_CONFIG);
+
+ /* Update multicast list - we cache all addresses so they won't
+ * change while HW is updated holding the command semaphor */
+ netif_tx_lock_bh(dev);
+ mlx4_en_cache_mclist(dev);
+ netif_tx_unlock_bh(dev);
+ for (mclist = priv->mc_list; mclist; mclist = mclist->next) {
+ mcast_addr = mlx4_en_mac_to_u64(mclist->dmi_addr);
+ mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
+ mcast_addr, 0, MLX4_MCAST_CONFIG);
+ }
+ err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
+ 0, MLX4_MCAST_ENABLE);
+ if (err)
+ mlx4_err(mdev, "Failed enabling multicast filter\n");
+
+ mlx4_en_clear_list(dev);
+ }
+out:
+ mutex_unlock(&mdev->state_lock);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void mlx4_en_netpoll(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_cq *cq;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ cq = &priv->rx_cq[i];
+ spin_lock_irqsave(&cq->lock, flags);
+ napi_synchronize(&cq->napi);
+ mlx4_en_process_rx_cq(dev, cq, 0);
+ spin_unlock_irqrestore(&cq->lock, flags);
+ }
+}
+#endif
+
+static void mlx4_en_tx_timeout(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ if (netif_msg_timer(priv))
+ mlx4_warn(mdev, "Tx timeout called on port:%d\n", priv->port);
+
+ if (netif_carrier_ok(dev)) {
+ priv->port_stats.tx_timeout++;
+ mlx4_dbg(DRV, priv, "Scheduling watchdog\n");
+ queue_work(mdev->workqueue, &priv->watchdog_task);
+ }
+}
+
+
+static struct net_device_stats *mlx4_en_get_stats(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+
+ spin_lock_bh(&priv->stats_lock);
+ memcpy(&priv->ret_stats, &priv->stats, sizeof(priv->stats));
+ spin_unlock_bh(&priv->stats_lock);
+
+ return &priv->ret_stats;
+}
+
+static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_cq *cq;
+ int i;
+
+ /* If we haven't received a specific coalescing setting
+ * (module param), we set the moderation paramters as follows:
+ * - moder_cnt is set to the number of mtu sized packets to
+ * satisfy our coelsing target.
+ * - moder_time is set to a fixed value.
+ */
+ priv->rx_frames = (mdev->profile.rx_moder_cnt ==
+ MLX4_EN_AUTO_CONF) ?
+ MLX4_EN_RX_COAL_TARGET /
+ priv->dev->mtu + 1 :
+ mdev->profile.rx_moder_cnt;
+ priv->rx_usecs = (mdev->profile.rx_moder_time ==
+ MLX4_EN_AUTO_CONF) ?
+ MLX4_EN_RX_COAL_TIME :
+ mdev->profile.rx_moder_time;
+ mlx4_dbg(INTR, priv, "Default coalesing params for mtu:%d - "
+ "rx_frames:%d rx_usecs:%d\n",
+ priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
+
+ /* Setup cq moderation params */
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ cq = &priv->rx_cq[i];
+ cq->moder_cnt = priv->rx_frames;
+ cq->moder_time = priv->rx_usecs;
+ }
+
+ for (i = 0; i < priv->tx_ring_num; i++) {
+ cq = &priv->tx_cq[i];
+ cq->moder_cnt = MLX4_EN_TX_COAL_PKTS;
+ cq->moder_time = MLX4_EN_TX_COAL_TIME;
+ }
+
+ /* Reset auto-moderation params */
+ priv->pkt_rate_low = MLX4_EN_RX_RATE_LOW;
+ priv->rx_usecs_low = MLX4_EN_RX_COAL_TIME_LOW;
+ priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH;
+ priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH;
+ priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL;
+ priv->adaptive_rx_coal = mdev->profile.auto_moder;
+ priv->last_moder_time = MLX4_EN_AUTO_CONF;
+ priv->last_moder_jiffies = 0;
+ priv->last_moder_packets = 0;
+ priv->last_moder_tx_packets = 0;
+ priv->last_moder_bytes = 0;
+}
+
+static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
+{
+ unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_cq *cq;
+ unsigned long packets;
+ unsigned long rate;
+ unsigned long avg_pkt_size;
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_pkt_diff;
+ unsigned long rx_pkt_diff;
+ int moder_time;
+ int i, err;
+
+ if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ)
+ return;
+
+ spin_lock_bh(&priv->stats_lock);
+ rx_packets = priv->stats.rx_packets;
+ rx_bytes = priv->stats.rx_bytes;
+ tx_packets = priv->stats.tx_packets;
+ spin_unlock_bh(&priv->stats_lock);
+
+ if (!priv->last_moder_jiffies || !period)
+ goto out;
+
+ tx_pkt_diff = ((unsigned long) (tx_packets -
+ priv->last_moder_tx_packets));
+ rx_pkt_diff = ((unsigned long) (rx_packets -
+ priv->last_moder_packets));
+ packets = max(tx_pkt_diff, rx_pkt_diff);
+ rate = packets * HZ / period;
+ avg_pkt_size = packets ? ((unsigned long) (rx_bytes -
+ priv->last_moder_bytes)) / packets : 0;
+
+ /* Apply auto-moderation only when packet rate exceeds a rate that
+ * it matters */
+ if (rate > MLX4_EN_RX_RATE_THRESH) {
+ /* If tx and rx packet rates are not balanced, assume that
+ * traffic is mainly BW bound and apply maximum moderation.
+ * Otherwise, moderate according to packet rate */
+ if (2 * tx_pkt_diff > 3 * rx_pkt_diff ||
+ 2 * rx_pkt_diff > 3 * tx_pkt_diff) {
+ moder_time = priv->rx_usecs_high;
+ } else {
+ if (rate < priv->pkt_rate_low)
+ moder_time = priv->rx_usecs_low;
+ else if (rate > priv->pkt_rate_high)
+ moder_time = priv->rx_usecs_high;
+ else
+ moder_time = (rate - priv->pkt_rate_low) *
+ (priv->rx_usecs_high - priv->rx_usecs_low) /
+ (priv->pkt_rate_high - priv->pkt_rate_low) +
+ priv->rx_usecs_low;
+ }
+ } else {
+ /* When packet rate is low, use default moderation rather than
+ * 0 to prevent interrupt storms if traffic suddenly increases */
+ moder_time = priv->rx_usecs;
+ }
+
+ mlx4_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n",
+ tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period);
+
+ mlx4_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu "
+ "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n",
+ priv->last_moder_time, moder_time, period, packets,
+ avg_pkt_size, rate);
+
+ if (moder_time != priv->last_moder_time) {
+ priv->last_moder_time = moder_time;
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ cq = &priv->rx_cq[i];
+ cq->moder_time = moder_time;
+ err = mlx4_en_set_cq_moder(priv, cq);
+ if (err) {
+ mlx4_err(mdev, "Failed modifying moderation for cq:%d "
+ "on port:%d\n", i, priv->port);
+ break;
+ }
+ }
+ }
+
+out:
+ priv->last_moder_packets = rx_packets;
+ priv->last_moder_tx_packets = tx_packets;
+ priv->last_moder_bytes = rx_bytes;
+ priv->last_moder_jiffies = jiffies;
+}
+
+static void mlx4_en_do_get_stats(struct work_struct *work)
+{
+ struct delayed_work *delay = container_of(work, struct delayed_work, work);
+ struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv,
+ stats_task);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0);
+ if (err)
+ mlx4_dbg(HW, priv, "Could not update stats for "
+ "port:%d\n", priv->port);
+
+ mutex_lock(&mdev->state_lock);
+ if (mdev->device_up) {
+ if (priv->port_up)
+ mlx4_en_auto_moderation(priv);
+
+ queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
+ }
+ mutex_unlock(&mdev->state_lock);
+}
+
+static void mlx4_en_linkstate(struct work_struct *work)
+{
+ struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+ linkstate_task);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int linkstate = priv->link_state;
+
+ mutex_lock(&mdev->state_lock);
+ /* If observable port state changed set carrier state and
+ * report to system log */
+ if (priv->last_link_state != linkstate) {
+ if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) {
+ if (netif_msg_link(priv))
+ mlx4_info(mdev, "Port %d - link down\n", priv->port);
+ netif_carrier_off(priv->dev);
+ } else {
+ if (netif_msg_link(priv))
+ mlx4_info(mdev, "Port %d - link up\n", priv->port);
+ netif_carrier_on(priv->dev);
+ }
+ }
+ priv->last_link_state = linkstate;
+ mutex_unlock(&mdev->state_lock);
+}
+
+
+static int mlx4_en_start_port(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_cq *cq;
+ struct mlx4_en_tx_ring *tx_ring;
+ struct mlx4_en_rx_ring *rx_ring;
+ int rx_index = 0;
+ int tx_index = 0;
+ u16 stride;
+ int err = 0;
+ int i;
+ int j;
+
+ if (priv->port_up) {
+ mlx4_dbg(DRV, priv, "start port called while port already up\n");
+ return 0;
+ }
+
+ /* Calculate Rx buf size */
+ dev->mtu = min(dev->mtu, priv->max_mtu);
+ mlx4_en_calc_rx_buf(dev);
+ mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size);
+ stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
+ DS_SIZE * priv->num_frags);
+ /* Configure rx cq's and rings */
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ cq = &priv->rx_cq[i];
+ rx_ring = &priv->rx_ring[i];
+
+ err = mlx4_en_activate_cq(priv, cq);
+ if (err) {
+ mlx4_err(mdev, "Failed activating Rx CQ\n");
+ goto rx_err;
+ }
+ for (j = 0; j < cq->size; j++)
+ cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK;
+ err = mlx4_en_set_cq_moder(priv, cq);
+ if (err) {
+ mlx4_err(mdev, "Failed setting cq moderation parameters");
+ mlx4_en_deactivate_cq(priv, cq);
+ goto cq_err;
+ }
+ mlx4_en_arm_cq(priv, cq);
+
+ ++rx_index;
+ }
+
+ err = mlx4_en_activate_rx_rings(priv);
+ if (err) {
+ mlx4_err(mdev, "Failed to activate RX rings\n");
+ goto cq_err;
+ }
+
+ err = mlx4_en_config_rss_steer(priv);
+ if (err) {
+ mlx4_err(mdev, "Failed configuring rss steering\n");
+ goto rx_err;
+ }
+
+ /* Configure tx cq's and rings */
+ for (i = 0; i < priv->tx_ring_num; i++) {
+ /* Configure cq */
+ cq = &priv->tx_cq[i];
+ err = mlx4_en_activate_cq(priv, cq);
+ if (err) {
+ mlx4_err(mdev, "Failed allocating Tx CQ\n");
+ goto tx_err;
+ }
+ err = mlx4_en_set_cq_moder(priv, cq);
+ if (err) {
+ mlx4_err(mdev, "Failed setting cq moderation parameters");
+ mlx4_en_deactivate_cq(priv, cq);
+ goto tx_err;
+ }
+ mlx4_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i);
+ cq->buf->wqe_index = cpu_to_be16(0xffff);
+
+ /* Configure ring */
+ tx_ring = &priv->tx_ring[i];
+ err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn,
+ priv->rx_ring[0].srq.srqn);
+ if (err) {
+ mlx4_err(mdev, "Failed allocating Tx ring\n");
+ mlx4_en_deactivate_cq(priv, cq);
+ goto tx_err;
+ }
+ /* Set initial ownership of all Tx TXBBs to SW (1) */
+ for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE)
+ *((u32 *) (tx_ring->buf + j)) = 0xffffffff;
+ ++tx_index;
+ }
+
+ /* Configure port */
+ err = mlx4_SET_PORT_general(mdev->dev, priv->port,
+ priv->rx_skb_size + ETH_FCS_LEN,
+ mdev->profile.tx_pause,
+ mdev->profile.tx_ppp,
+ mdev->profile.rx_pause,
+ mdev->profile.rx_ppp);
+ if (err) {
+ mlx4_err(mdev, "Failed setting port general configurations"
+ " for port %d, with error %d\n", priv->port, err);
+ goto tx_err;
+ }
+ /* Set default qp number */
+ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0);
+ if (err) {
+ mlx4_err(mdev, "Failed setting default qp numbers\n");
+ goto tx_err;
+ }
+ /* Set port mac number */
+ mlx4_dbg(DRV, priv, "Setting mac for port %d\n", priv->port);
+ err = mlx4_register_mac(mdev->dev, priv->port,
+ priv->mac, &priv->mac_index);
+ if (err) {
+ mlx4_err(mdev, "Failed setting port mac\n");
+ goto tx_err;
+ }
+
+ /* Init port */
+ mlx4_dbg(HW, priv, "Initializing port\n");
+ err = mlx4_INIT_PORT(mdev->dev, priv->port);
+ if (err) {
+ mlx4_err(mdev, "Failed Initializing port\n");
+ goto mac_err;
+ }
+
+ /* Schedule multicast task to populate multicast list */
+ queue_work(mdev->workqueue, &priv->mcast_task);
+
+ priv->port_up = true;
+ netif_start_queue(dev);
+ return 0;
+
+mac_err:
+ mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index);
+tx_err:
+ while (tx_index--) {
+ mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[tx_index]);
+ mlx4_en_deactivate_cq(priv, &priv->tx_cq[tx_index]);
+ }
+
+ mlx4_en_release_rss_steer(priv);
+rx_err:
+ for (i = 0; i < priv->rx_ring_num; i++)
+ mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[rx_index]);
+cq_err:
+ while (rx_index--)
+ mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
+
+ return err; /* need to close devices */
+}
+
+
+static void mlx4_en_stop_port(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int i;
+
+ if (!priv->port_up) {
+ mlx4_dbg(DRV, priv, "stop port (%d) called while port already down\n",
+ priv->port);
+ return;
+ }
+ netif_stop_queue(dev);
+
+ /* Synchronize with tx routine */
+ netif_tx_lock_bh(dev);
+ priv->port_up = false;
+ netif_tx_unlock_bh(dev);
+
+ /* close port*/
+ mlx4_CLOSE_PORT(mdev->dev, priv->port);
+
+ /* Unregister Mac address for the port */
+ mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index);
+
+ /* Free TX Rings */
+ for (i = 0; i < priv->tx_ring_num; i++) {
+ mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[i]);
+ mlx4_en_deactivate_cq(priv, &priv->tx_cq[i]);
+ }
+ msleep(10);
+
+ for (i = 0; i < priv->tx_ring_num; i++)
+ mlx4_en_free_tx_buf(dev, &priv->tx_ring[i]);
+
+ /* Free RSS qps */
+ mlx4_en_release_rss_steer(priv);
+
+ /* Free RX Rings */
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
+ while (test_bit(NAPI_STATE_SCHED, &priv->rx_cq[i].napi.state))
+ msleep(1);
+ mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]);
+ }
+}
+
+static void mlx4_en_restart(struct work_struct *work)
+{
+ struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+ watchdog_task);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct net_device *dev = priv->dev;
+
+ mlx4_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port);
+ mlx4_en_stop_port(dev);
+ if (mlx4_en_start_port(dev))
+ mlx4_err(mdev, "Failed restarting port %d\n", priv->port);
+}
+
+
+static int mlx4_en_open(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int i;
+ int err = 0;
+
+ mutex_lock(&mdev->state_lock);
+
+ if (!mdev->device_up) {
+ mlx4_err(mdev, "Cannot open - device down/disabled\n");
+ err = -EBUSY;
+ goto out;
+ }
+
+ /* Reset HW statistics and performance counters */
+ if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1))
+ mlx4_dbg(HW, priv, "Failed dumping statistics\n");
+
+ memset(&priv->stats, 0, sizeof(priv->stats));
+ memset(&priv->pstats, 0, sizeof(priv->pstats));
+
+ for (i = 0; i < priv->tx_ring_num; i++) {
+ priv->tx_ring[i].bytes = 0;
+ priv->tx_ring[i].packets = 0;
+ }
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ priv->rx_ring[i].bytes = 0;
+ priv->rx_ring[i].packets = 0;
+ }
+
+ mlx4_en_set_default_moderation(priv);
+ err = mlx4_en_start_port(dev);
+ if (err)
+ mlx4_err(mdev, "Failed starting port:%d\n", priv->port);
+
+out:
+ mutex_unlock(&mdev->state_lock);
+ return err;
+}
+
+
+static int mlx4_en_close(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ if (netif_msg_ifdown(priv))
+ mlx4_info(mdev, "Close called for port:%d\n", priv->port);
+
+ mutex_lock(&mdev->state_lock);
+
+ mlx4_en_stop_port(dev);
+ netif_carrier_off(dev);
+
+ mutex_unlock(&mdev->state_lock);
+ return 0;
+}
+
+static void mlx4_en_free_resources(struct mlx4_en_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->tx_ring_num; i++) {
+ if (priv->tx_ring[i].tx_info)
+ mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]);
+ if (priv->tx_cq[i].buf)
+ mlx4_en_destroy_cq(priv, &priv->tx_cq[i]);
+ }
+
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ if (priv->rx_ring[i].rx_info)
+ mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i]);
+ if (priv->rx_cq[i].buf)
+ mlx4_en_destroy_cq(priv, &priv->rx_cq[i]);
+ }
+}
+
+static int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_port_profile *prof = priv->prof;
+ int i;
+
+ /* Create tx Rings */
+ for (i = 0; i < priv->tx_ring_num; i++) {
+ if (mlx4_en_create_cq(priv, &priv->tx_cq[i],
+ prof->tx_ring_size, i, TX))
+ goto err;
+
+ if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i],
+ prof->tx_ring_size, TXBB_SIZE))
+ goto err;
+ }
+
+ /* Create rx Rings */
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ if (mlx4_en_create_cq(priv, &priv->rx_cq[i],
+ prof->rx_ring_size, i, RX))
+ goto err;
+
+ if (mlx4_en_create_rx_ring(priv, &priv->rx_ring[i],
+ prof->rx_ring_size, priv->stride))
+ goto err;
+ }
+
+ return 0;
+
+err:
+ mlx4_err(mdev, "Failed to allocate NIC resources\n");
+ return -ENOMEM;
+}
+
+
+void mlx4_en_destroy_netdev(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ mlx4_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port);
+
+ /* Unregister device - this will close the port if it was up */
+ if (priv->registered)
+ unregister_netdev(dev);
+
+ if (priv->allocated)
+ mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE);
+
+ cancel_delayed_work(&priv->stats_task);
+ cancel_delayed_work(&priv->refill_task);
+ /* flush any pending task for this netdev */
+ flush_workqueue(mdev->workqueue);
+
+ /* Detach the netdev so tasks would not attempt to access it */
+ mutex_lock(&mdev->state_lock);
+ mdev->pndev[priv->port] = NULL;
+ mutex_unlock(&mdev->state_lock);
+
+ mlx4_en_free_resources(priv);
+ free_netdev(dev);
+}
+
+static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err = 0;
+
+ mlx4_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n",
+ dev->mtu, new_mtu);
+
+ if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) {
+ mlx4_err(mdev, "Bad MTU size:%d.\n", new_mtu);
+ return -EPERM;
+ }
+ dev->mtu = new_mtu;
+
+ if (netif_running(dev)) {
+ mutex_lock(&mdev->state_lock);
+ if (!mdev->device_up) {
+ /* NIC is probably restarting - let watchdog task reset
+ * the port */
+ mlx4_dbg(DRV, priv, "Change MTU called with card down!?\n");
+ } else {
+ mlx4_en_stop_port(dev);
+ mlx4_en_set_default_moderation(priv);
+ err = mlx4_en_start_port(dev);
+ if (err) {
+ mlx4_err(mdev, "Failed restarting port:%d\n",
+ priv->port);
+ queue_work(mdev->workqueue, &priv->watchdog_task);
+ }
+ }
+ mutex_unlock(&mdev->state_lock);
+ }
+ return 0;
+}
+
+int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
+ struct mlx4_en_port_profile *prof)
+{
+ struct net_device *dev;
+ struct mlx4_en_priv *priv;
+ int i;
+ int err;
+
+ dev = alloc_etherdev(sizeof(struct mlx4_en_priv));
+ if (dev == NULL) {
+ mlx4_err(mdev, "Net device allocation failed\n");
+ return -ENOMEM;
+ }
+
+ SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev);
+
+ /*
+ * Initialize driver private data
+ */
+
+ priv = netdev_priv(dev);
+ memset(priv, 0, sizeof(struct mlx4_en_priv));
+ priv->dev = dev;
+ priv->mdev = mdev;
+ priv->prof = prof;
+ priv->port = port;
+ priv->port_up = false;
+ priv->rx_csum = 1;
+ priv->flags = prof->flags;
+ priv->tx_ring_num = prof->tx_ring_num;
+ priv->rx_ring_num = prof->rx_ring_num;
+ priv->mc_list = NULL;
+ priv->mac_index = -1;
+ priv->msg_enable = MLX4_EN_MSG_LEVEL;
+ spin_lock_init(&priv->stats_lock);
+ INIT_WORK(&priv->mcast_task, mlx4_en_do_set_multicast);
+ INIT_WORK(&priv->mac_task, mlx4_en_do_set_mac);
+ INIT_DELAYED_WORK(&priv->refill_task, mlx4_en_rx_refill);
+ INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
+ INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
+ INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
+
+ /* Query for default mac and max mtu */
+ priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
+ priv->mac = mdev->dev->caps.def_mac[priv->port];
+ if (ILLEGAL_MAC(priv->mac)) {
+ mlx4_err(mdev, "Port: %d, invalid mac burned: 0x%llx, quiting\n",
+ priv->port, priv->mac);
+ err = -EINVAL;
+ goto out;
+ }
+
+ priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
+ DS_SIZE * MLX4_EN_MAX_RX_FRAGS);
+ err = mlx4_en_alloc_resources(priv);
+ if (err)
+ goto out;
+
+ /* Populate Rx default RSS mappings */
+ mlx4_en_set_default_rss_map(priv, &priv->rss_map, priv->rx_ring_num *
+ RSS_FACTOR, priv->rx_ring_num);
+ /* Allocate page for receive rings */
+ err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
+ MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE);
+ if (err) {
+ mlx4_err(mdev, "Failed to allocate page for rx qps\n");
+ goto out;
+ }
+ priv->allocated = 1;
+
+ /* Populate Tx priority mappings */
+ mlx4_en_set_prio_map(priv, priv->tx_prio_map, prof->tx_ring_num);
+
+ /*
+ * Initialize netdev entry points
+ */
+
+ dev->open = &mlx4_en_open;
+ dev->stop = &mlx4_en_close;
+ dev->hard_start_xmit = &mlx4_en_xmit;
+ dev->get_stats = &mlx4_en_get_stats;
+ dev->set_multicast_list = &mlx4_en_set_multicast;
+ dev->set_mac_address = &mlx4_en_set_mac;
+ dev->change_mtu = &mlx4_en_change_mtu;
+ dev->tx_timeout = &mlx4_en_tx_timeout;
+ dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT;
+ dev->vlan_rx_register = mlx4_en_vlan_rx_register;
+ dev->vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid;
+ dev->vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = mlx4_en_netpoll;
+#endif
+ SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
+
+ /* Set defualt MAC */
+ dev->addr_len = ETH_ALEN;
+ for (i = 0; i < ETH_ALEN; i++)
+ dev->dev_addr[ETH_ALEN - 1 - i] =
+ (u8) (priv->mac >> (8 * i));
+
+ /*
+ * Set driver features
+ */
+ dev->features |= NETIF_F_SG;
+ dev->features |= NETIF_F_HW_CSUM;
+ dev->features |= NETIF_F_HIGHDMA;
+ dev->features |= NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+ if (mdev->profile.num_lro)
+ dev->features |= NETIF_F_LRO;
+ if (mdev->LSO_support) {
+ dev->features |= NETIF_F_TSO;
+ dev->features |= NETIF_F_TSO6;
+ }
+
+ mdev->pndev[port] = dev;
+
+ netif_carrier_off(dev);
+ err = register_netdev(dev);
+ if (err) {
+ mlx4_err(mdev, "Netdev registration failed\n");
+ goto out;
+ }
+ priv->registered = 1;
+ queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
+ return 0;
+
+out:
+ mlx4_en_destroy_netdev(dev);
+ return err;
+}
+
diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_params.c
new file mode 100644
index 00000000000..c2e69b1bcd0
--- /dev/null
+++ b/drivers/net/mlx4/en_params.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+
+#include "mlx4_en.h"
+#include "en_port.h"
+
+#define MLX4_EN_PARM_INT(X, def_val, desc) \
+ static unsigned int X = def_val;\
+ module_param(X , uint, 0444); \
+ MODULE_PARM_DESC(X, desc);
+
+
+/*
+ * Device scope module parameters
+ */
+
+
+/* Use a XOR rathern than Toeplitz hash function for RSS */
+MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS");
+
+/* RSS hash type mask - default to <saddr, daddr, sport, dport> */
+MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask");
+
+/* Number of LRO sessions per Rx ring (rounded up to a power of two) */
+MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS,
+ "Number of LRO sessions per ring or disabled (0)");
+
+/* Priority pausing */
+MLX4_EN_PARM_INT(pptx, MLX4_EN_DEF_TX_PAUSE,
+ "Pause policy on TX: 0 never generate pause frames "
+ "1 generate pause frames according to RX buffer threshold");
+MLX4_EN_PARM_INT(pprx, MLX4_EN_DEF_RX_PAUSE,
+ "Pause policy on RX: 0 ignore received pause frames "
+ "1 respect received pause frames");
+MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
+ " Per priority bit mask");
+MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
+ " Per priority bit mask");
+
+/* Interrupt moderation tunning */
+MLX4_EN_PARM_INT(rx_moder_cnt, MLX4_EN_AUTO_CONF,
+ "Max coalesced descriptors for Rx interrupt moderation");
+MLX4_EN_PARM_INT(rx_moder_time, MLX4_EN_AUTO_CONF,
+ "Timeout following last packet for Rx interrupt moderation");
+MLX4_EN_PARM_INT(auto_moder, 1, "Enable dynamic interrupt moderation");
+
+MLX4_EN_PARM_INT(rx_ring_num1, 0, "Number or Rx rings for port 1 (0 = #cores)");
+MLX4_EN_PARM_INT(rx_ring_num2, 0, "Number or Rx rings for port 2 (0 = #cores)");
+
+MLX4_EN_PARM_INT(tx_ring_size1, MLX4_EN_AUTO_CONF, "Tx ring size for port 1");
+MLX4_EN_PARM_INT(tx_ring_size2, MLX4_EN_AUTO_CONF, "Tx ring size for port 2");
+MLX4_EN_PARM_INT(rx_ring_size1, MLX4_EN_AUTO_CONF, "Rx ring size for port 1");
+MLX4_EN_PARM_INT(rx_ring_size2, MLX4_EN_AUTO_CONF, "Rx ring size for port 2");
+
+
+int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
+{
+ struct mlx4_en_profile *params = &mdev->profile;
+
+ params->rx_moder_cnt = min_t(int, rx_moder_cnt, MLX4_EN_AUTO_CONF);
+ params->rx_moder_time = min_t(int, rx_moder_time, MLX4_EN_AUTO_CONF);
+ params->auto_moder = auto_moder;
+ params->rss_xor = (rss_xor != 0);
+ params->rss_mask = rss_mask & 0x1f;
+ params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS);
+ params->rx_pause = pprx;
+ params->rx_ppp = pfcrx;
+ params->tx_pause = pptx;
+ params->tx_ppp = pfctx;
+ if (params->rx_ppp || params->tx_ppp) {
+ params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM;
+ params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM;
+ } else {
+ params->prof[1].tx_ring_num = 1;
+ params->prof[2].tx_ring_num = 1;
+ }
+ params->prof[1].rx_ring_num = min_t(int, rx_ring_num1, MAX_RX_RINGS);
+ params->prof[2].rx_ring_num = min_t(int, rx_ring_num2, MAX_RX_RINGS);
+
+ if (tx_ring_size1 == MLX4_EN_AUTO_CONF)
+ tx_ring_size1 = MLX4_EN_DEF_TX_RING_SIZE;
+ params->prof[1].tx_ring_size =
+ (tx_ring_size1 < MLX4_EN_MIN_TX_SIZE) ?
+ MLX4_EN_MIN_TX_SIZE : roundup_pow_of_two(tx_ring_size1);
+
+ if (tx_ring_size2 == MLX4_EN_AUTO_CONF)
+ tx_ring_size2 = MLX4_EN_DEF_TX_RING_SIZE;
+ params->prof[2].tx_ring_size =
+ (tx_ring_size2 < MLX4_EN_MIN_TX_SIZE) ?
+ MLX4_EN_MIN_TX_SIZE : roundup_pow_of_two(tx_ring_size2);
+
+ if (rx_ring_size1 == MLX4_EN_AUTO_CONF)
+ rx_ring_size1 = MLX4_EN_DEF_RX_RING_SIZE;
+ params->prof[1].rx_ring_size =
+ (rx_ring_size1 < MLX4_EN_MIN_RX_SIZE) ?
+ MLX4_EN_MIN_RX_SIZE : roundup_pow_of_two(rx_ring_size1);
+
+ if (rx_ring_size2 == MLX4_EN_AUTO_CONF)
+ rx_ring_size2 = MLX4_EN_DEF_RX_RING_SIZE;
+ params->prof[2].rx_ring_size =
+ (rx_ring_size2 < MLX4_EN_MIN_RX_SIZE) ?
+ MLX4_EN_MIN_RX_SIZE : roundup_pow_of_two(rx_ring_size2);
+ return 0;
+}
+
+
+/*
+ * Ethtool support
+ */
+
+static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv)
+{
+ int i;
+
+ priv->port_stats.lro_aggregated = 0;
+ priv->port_stats.lro_flushed = 0;
+ priv->port_stats.lro_no_desc = 0;
+
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ priv->port_stats.lro_aggregated += priv->rx_ring[i].lro.stats.aggregated;
+ priv->port_stats.lro_flushed += priv->rx_ring[i].lro.stats.flushed;
+ priv->port_stats.lro_no_desc += priv->rx_ring[i].lro.stats.no_desc;
+ }
+}
+
+static void
+mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id);
+ strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32);
+ sprintf(drvinfo->fw_version, "%d.%d.%d",
+ (u16) (mdev->dev->caps.fw_ver >> 32),
+ (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff),
+ (u16) (mdev->dev->caps.fw_ver & 0xffff));
+ strncpy(drvinfo->bus_info, pci_name(mdev->dev->pdev), 32);
+ drvinfo->n_stats = 0;
+ drvinfo->regdump_len = 0;
+ drvinfo->eedump_len = 0;
+}
+
+static u32 mlx4_en_get_tso(struct net_device *dev)
+{
+ return (dev->features & NETIF_F_TSO) != 0;
+}
+
+static int mlx4_en_set_tso(struct net_device *dev, u32 data)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+
+ if (data) {
+ if (!priv->mdev->LSO_support)
+ return -EPERM;
+ dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ } else
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ return 0;
+}
+
+static u32 mlx4_en_get_rx_csum(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ return priv->rx_csum;
+}
+
+static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ priv->rx_csum = (data != 0);
+ return 0;
+}
+
+static const char main_strings[][ETH_GSTRING_LEN] = {
+ "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+ "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+ "rx_length_errors", "rx_over_errors", "rx_crc_errors",
+ "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+ "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+ "tx_heartbeat_errors", "tx_window_errors",
+
+ /* port statistics */
+ "lro_aggregated", "lro_flushed", "lro_no_desc", "tso_packets",
+ "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
+ "rx_csum_good", "rx_csum_none", "tx_chksum_offload",
+
+ /* packet statistics */
+ "broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3",
+ "rx_prio_4", "rx_prio_5", "rx_prio_6", "rx_prio_7", "tx_prio_0",
+ "tx_prio_1", "tx_prio_2", "tx_prio_3", "tx_prio_4", "tx_prio_5",
+ "tx_prio_6", "tx_prio_7",
+};
+#define NUM_MAIN_STATS 21
+#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS)
+
+static u32 mlx4_en_get_msglevel(struct net_device *dev)
+{
+ return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable;
+}
+
+static void mlx4_en_set_msglevel(struct net_device *dev, u32 val)
+{
+ ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable = val;
+}
+
+static void mlx4_en_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ return;
+}
+
+static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+
+ if (sset != ETH_SS_STATS)
+ return -EOPNOTSUPP;
+
+ return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2;
+}
+
+static void mlx4_en_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, uint64_t *data)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int index = 0;
+ int i;
+
+ spin_lock_bh(&priv->stats_lock);
+
+ mlx4_en_update_lro_stats(priv);
+
+ for (i = 0; i < NUM_MAIN_STATS; i++)
+ data[index++] = ((unsigned long *) &priv->stats)[i];
+ for (i = 0; i < NUM_PORT_STATS; i++)
+ data[index++] = ((unsigned long *) &priv->port_stats)[i];
+ for (i = 0; i < priv->tx_ring_num; i++) {
+ data[index++] = priv->tx_ring[i].packets;
+ data[index++] = priv->tx_ring[i].bytes;
+ }
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ data[index++] = priv->rx_ring[i].packets;
+ data[index++] = priv->rx_ring[i].bytes;
+ }
+ for (i = 0; i < NUM_PKT_STATS; i++)
+ data[index++] = ((unsigned long *) &priv->pkstats)[i];
+ spin_unlock_bh(&priv->stats_lock);
+
+}
+
+static void mlx4_en_get_strings(struct net_device *dev,
+ uint32_t stringset, uint8_t *data)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int index = 0;
+ int i;
+
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ /* Add main counters */
+ for (i = 0; i < NUM_MAIN_STATS; i++)
+ strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
+ for (i = 0; i < NUM_PORT_STATS; i++)
+ strcpy(data + (index++) * ETH_GSTRING_LEN,
+ main_strings[i + NUM_MAIN_STATS]);
+ for (i = 0; i < priv->tx_ring_num; i++) {
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "tx%d_packets", i);
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "tx%d_bytes", i);
+ }
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "rx%d_packets", i);
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "rx%d_bytes", i);
+ }
+ for (i = 0; i < NUM_PKT_STATS; i++)
+ strcpy(data + (index++) * ETH_GSTRING_LEN,
+ main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]);
+}
+
+static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->supported = SUPPORTED_10000baseT_Full;
+ cmd->advertising = SUPPORTED_10000baseT_Full;
+ if (netif_carrier_ok(dev)) {
+ cmd->speed = SPEED_10000;
+ cmd->duplex = DUPLEX_FULL;
+ } else {
+ cmd->speed = -1;
+ cmd->duplex = -1;
+ }
+ return 0;
+}
+
+static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ if ((cmd->autoneg == AUTONEG_ENABLE) ||
+ (cmd->speed != SPEED_10000) || (cmd->duplex != DUPLEX_FULL))
+ return -EINVAL;
+
+ /* Nothing to change */
+ return 0;
+}
+
+static int mlx4_en_get_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *coal)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+
+ coal->tx_coalesce_usecs = 0;
+ coal->tx_max_coalesced_frames = 0;
+ coal->rx_coalesce_usecs = priv->rx_usecs;
+ coal->rx_max_coalesced_frames = priv->rx_frames;
+
+ coal->pkt_rate_low = priv->pkt_rate_low;
+ coal->rx_coalesce_usecs_low = priv->rx_usecs_low;
+ coal->pkt_rate_high = priv->pkt_rate_high;
+ coal->rx_coalesce_usecs_high = priv->rx_usecs_high;
+ coal->rate_sample_interval = priv->sample_interval;
+ coal->use_adaptive_rx_coalesce = priv->adaptive_rx_coal;
+ return 0;
+}
+
+static int mlx4_en_set_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *coal)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int err, i;
+
+ priv->rx_frames = (coal->rx_max_coalesced_frames ==
+ MLX4_EN_AUTO_CONF) ?
+ MLX4_EN_RX_COAL_TARGET /
+ priv->dev->mtu + 1 :
+ coal->rx_max_coalesced_frames;
+ priv->rx_usecs = (coal->rx_coalesce_usecs ==
+ MLX4_EN_AUTO_CONF) ?
+ MLX4_EN_RX_COAL_TIME :
+ coal->rx_coalesce_usecs;
+
+ /* Set adaptive coalescing params */
+ priv->pkt_rate_low = coal->pkt_rate_low;
+ priv->rx_usecs_low = coal->rx_coalesce_usecs_low;
+ priv->pkt_rate_high = coal->pkt_rate_high;
+ priv->rx_usecs_high = coal->rx_coalesce_usecs_high;
+ priv->sample_interval = coal->rate_sample_interval;
+ priv->adaptive_rx_coal = coal->use_adaptive_rx_coalesce;
+ priv->last_moder_time = MLX4_EN_AUTO_CONF;
+ if (priv->adaptive_rx_coal)
+ return 0;
+
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ priv->rx_cq[i].moder_cnt = priv->rx_frames;
+ priv->rx_cq[i].moder_time = priv->rx_usecs;
+ err = mlx4_en_set_cq_moder(priv, &priv->rx_cq[i]);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int mlx4_en_set_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ mdev->profile.tx_pause = pause->tx_pause != 0;
+ mdev->profile.rx_pause = pause->rx_pause != 0;
+ err = mlx4_SET_PORT_general(mdev->dev, priv->port,
+ priv->rx_skb_size + ETH_FCS_LEN,
+ mdev->profile.tx_pause,
+ mdev->profile.tx_ppp,
+ mdev->profile.rx_pause,
+ mdev->profile.rx_ppp);
+ if (err)
+ mlx4_err(mdev, "Failed setting pause params to\n");
+
+ return err;
+}
+
+static void mlx4_en_get_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ pause->tx_pause = mdev->profile.tx_pause;
+ pause->rx_pause = mdev->profile.rx_pause;
+}
+
+static void mlx4_en_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *param)
+{
+ struct mlx4_en_priv *priv = netdev_priv(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_pending = mdev->profile.prof[priv->port].rx_ring_size;
+ param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size;
+}
+
+const struct ethtool_ops mlx4_en_ethtool_ops = {
+ .get_drvinfo = mlx4_en_get_drvinfo,
+ .get_settings = mlx4_en_get_settings,
+ .set_settings = mlx4_en_set_settings,
+#ifdef NETIF_F_TSO
+ .get_tso = mlx4_en_get_tso,
+ .set_tso = mlx4_en_set_tso,
+#endif
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_link = ethtool_op_get_link,
+ .get_rx_csum = mlx4_en_get_rx_csum,
+ .set_rx_csum = mlx4_en_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
+ .get_strings = mlx4_en_get_strings,
+ .get_sset_count = mlx4_en_get_sset_count,
+ .get_ethtool_stats = mlx4_en_get_ethtool_stats,
+ .get_wol = mlx4_en_get_wol,
+ .get_msglevel = mlx4_en_get_msglevel,
+ .set_msglevel = mlx4_en_set_msglevel,
+ .get_coalesce = mlx4_en_get_coalesce,
+ .set_coalesce = mlx4_en_set_coalesce,
+ .get_pauseparam = mlx4_en_get_pauseparam,
+ .set_pauseparam = mlx4_en_set_pauseparam,
+ .get_ringparam = mlx4_en_get_ringparam,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = ethtool_op_set_flags,
+};
+
+
+
+
+
diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c
new file mode 100644
index 00000000000..c5a4c038975
--- /dev/null
+++ b/drivers/net/mlx4/en_port.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+
+#include <linux/if_vlan.h>
+
+#include <linux/mlx4/device.h>
+#include <linux/mlx4/cmd.h>
+
+#include "en_port.h"
+#include "mlx4_en.h"
+
+
+int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port,
+ u64 mac, u64 clear, u8 mode)
+{
+ return mlx4_cmd(dev, (mac | (clear << 63)), port, mode,
+ MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B);
+}
+
+int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, u8 port, struct vlan_group *grp)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_set_vlan_fltr_mbox *filter;
+ int i;
+ int j;
+ int index = 0;
+ u32 entry;
+ int err = 0;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ filter = mailbox->buf;
+ if (grp) {
+ memset(filter, 0, sizeof *filter);
+ for (i = VLAN_FLTR_SIZE - 1; i >= 0; i--) {
+ entry = 0;
+ for (j = 0; j < 32; j++)
+ if (vlan_group_get_device(grp, index++))
+ entry |= 1 << j;
+ filter->entry[i] = cpu_to_be32(entry);
+ }
+ } else {
+ /* When no vlans are configured we block all vlans */
+ memset(filter, 0, sizeof(*filter));
+ }
+ err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_VLAN_FLTR,
+ MLX4_CMD_TIME_CLASS_B);
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+
+
+int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
+ u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_set_port_general_context *context;
+ int err;
+ u32 in_mod;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ context = mailbox->buf;
+ memset(context, 0, sizeof *context);
+
+ context->flags = SET_PORT_GEN_ALL_VALID;
+ context->mtu = cpu_to_be16(mtu);
+ context->pptx = (pptx * (!pfctx)) << 7;
+ context->pfctx = pfctx;
+ context->pprx = (pprx * (!pfcrx)) << 7;
+ context->pfcrx = pfcrx;
+
+ in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
+ err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
+ MLX4_CMD_TIME_CLASS_B);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+
+int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
+ u8 promisc)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_set_port_rqp_calc_context *context;
+ int err;
+ u32 in_mod;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ context = mailbox->buf;
+ memset(context, 0, sizeof *context);
+
+ context->base_qpn = cpu_to_be32(base_qpn);
+ context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | base_qpn);
+ context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_SHIFT | base_qpn);
+ context->intra_no_vlan = 0;
+ context->no_vlan = MLX4_NO_VLAN_IDX;
+ context->intra_vlan_miss = 0;
+ context->vlan_miss = MLX4_VLAN_MISS_IDX;
+
+ in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port;
+ err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
+ MLX4_CMD_TIME_CLASS_B);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+
+
+int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
+{
+ struct mlx4_en_stat_out_mbox *mlx4_en_stats;
+ struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]);
+ struct net_device_stats *stats = &priv->stats;
+ struct mlx4_cmd_mailbox *mailbox;
+ u64 in_mod = reset << 8 | port;
+ int err;
+
+ mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ memset(mailbox->buf, 0, sizeof(*mlx4_en_stats));
+ err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod, 0,
+ MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B);
+ if (err)
+ goto out;
+
+ mlx4_en_stats = mailbox->buf;
+
+ spin_lock_bh(&priv->stats_lock);
+
+ stats->rx_packets = be32_to_cpu(mlx4_en_stats->RTOTFRMS) -
+ be32_to_cpu(mlx4_en_stats->RDROP);
+ stats->tx_packets = be64_to_cpu(mlx4_en_stats->TTOT_prio_0) +
+ be64_to_cpu(mlx4_en_stats->TTOT_prio_1) +
+ be64_to_cpu(mlx4_en_stats->TTOT_prio_2) +
+ be64_to_cpu(mlx4_en_stats->TTOT_prio_3) +
+ be64_to_cpu(mlx4_en_stats->TTOT_prio_4) +
+ be64_to_cpu(mlx4_en_stats->TTOT_prio_5) +
+ be64_to_cpu(mlx4_en_stats->TTOT_prio_6) +
+ be64_to_cpu(mlx4_en_stats->TTOT_prio_7) +
+ be64_to_cpu(mlx4_en_stats->TTOT_novlan) +
+ be64_to_cpu(mlx4_en_stats->TTOT_loopbk);
+ stats->rx_bytes = be64_to_cpu(mlx4_en_stats->ROCT_prio_0) +
+ be64_to_cpu(mlx4_en_stats->ROCT_prio_1) +
+ be64_to_cpu(mlx4_en_stats->ROCT_prio_2) +
+ be64_to_cpu(mlx4_en_stats->ROCT_prio_3) +
+ be64_to_cpu(mlx4_en_stats->ROCT_prio_4) +
+ be64_to_cpu(mlx4_en_stats->ROCT_prio_5) +
+ be64_to_cpu(mlx4_en_stats->ROCT_prio_6) +
+ be64_to_cpu(mlx4_en_stats->ROCT_prio_7) +
+ be64_to_cpu(mlx4_en_stats->ROCT_novlan);
+
+ stats->tx_bytes = be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_0) +
+ be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_1) +
+ be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_2) +
+ be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_3) +
+ be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_4) +
+ be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_5) +
+ be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_6) +
+ be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_7) +
+ be64_to_cpu(mlx4_en_stats->TTTLOCT_novlan) +
+ be64_to_cpu(mlx4_en_stats->TTTLOCT_loopbk);
+
+ stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) +
+ be32_to_cpu(mlx4_en_stats->RdropLength) +
+ be32_to_cpu(mlx4_en_stats->RJBBR) +
+ be32_to_cpu(mlx4_en_stats->RCRC) +
+ be32_to_cpu(mlx4_en_stats->RRUNT);
+ stats->tx_errors = be32_to_cpu(mlx4_en_stats->TDROP);
+ stats->multicast = be64_to_cpu(mlx4_en_stats->MCAST_prio_0) +
+ be64_to_cpu(mlx4_en_stats->MCAST_prio_1) +
+ be64_to_cpu(mlx4_en_stats->MCAST_prio_2) +
+ be64_to_cpu(mlx4_en_stats->MCAST_prio_3) +
+ be64_to_cpu(mlx4_en_stats->MCAST_prio_4) +
+ be64_to_cpu(mlx4_en_stats->MCAST_prio_5) +
+ be64_to_cpu(mlx4_en_stats->MCAST_prio_6) +
+ be64_to_cpu(mlx4_en_stats->MCAST_prio_7) +
+ be64_to_cpu(mlx4_en_stats->MCAST_novlan);
+ stats->collisions = 0;
+ stats->rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength);
+ stats->rx_over_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
+ stats->rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC);
+ stats->rx_frame_errors = 0;
+ stats->rx_fifo_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
+ stats->rx_missed_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
+ stats->tx_aborted_errors = 0;
+ stats->tx_carrier_errors = 0;
+ stats->tx_fifo_errors = 0;
+ stats->tx_heartbeat_errors = 0;
+ stats->tx_window_errors = 0;
+
+ priv->pkstats.broadcast =
+ be64_to_cpu(mlx4_en_stats->RBCAST_prio_0) +
+ be64_to_cpu(mlx4_en_stats->RBCAST_prio_1) +
+ be64_to_cpu(mlx4_en_stats->RBCAST_prio_2) +
+ be64_to_cpu(mlx4_en_stats->RBCAST_prio_3) +
+ be64_to_cpu(mlx4_en_stats->RBCAST_prio_4) +
+ be64_to_cpu(mlx4_en_stats->RBCAST_prio_5) +
+ be64_to_cpu(mlx4_en_stats->RBCAST_prio_6) +
+ be64_to_cpu(mlx4_en_stats->RBCAST_prio_7) +
+ be64_to_cpu(mlx4_en_stats->RBCAST_novlan);
+ priv->pkstats.rx_prio[0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_0);
+ priv->pkstats.rx_prio[1] = be64_to_cpu(mlx4_en_stats->RTOT_prio_1);
+ priv->pkstats.rx_prio[2] = be64_to_cpu(mlx4_en_stats->RTOT_prio_2);
+ priv->pkstats.rx_prio[3] = be64_to_cpu(mlx4_en_stats->RTOT_prio_3);
+ priv->pkstats.rx_prio[4] = be64_to_cpu(mlx4_en_stats->RTOT_prio_4);
+ priv->pkstats.rx_prio[5] = be64_to_cpu(mlx4_en_stats->RTOT_prio_5);
+ priv->pkstats.rx_prio[6] = be64_to_cpu(mlx4_en_stats->RTOT_prio_6);
+ priv->pkstats.rx_prio[7] = be64_to_cpu(mlx4_en_stats->RTOT_prio_7);
+ priv->pkstats.tx_prio[0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_0);
+ priv->pkstats.tx_prio[1] = be64_to_cpu(mlx4_en_stats->TTOT_prio_1);
+ priv->pkstats.tx_prio[2] = be64_to_cpu(mlx4_en_stats->TTOT_prio_2);
+ priv->pkstats.tx_prio[3] = be64_to_cpu(mlx4_en_stats->TTOT_prio_3);
+ priv->pkstats.tx_prio[4] = be64_to_cpu(mlx4_en_stats->TTOT_prio_4);
+ priv->pkstats.tx_prio[5] = be64_to_cpu(mlx4_en_stats->TTOT_prio_5);
+ priv->pkstats.tx_prio[6] = be64_to_cpu(mlx4_en_stats->TTOT_prio_6);
+ priv->pkstats.tx_prio[7] = be64_to_cpu(mlx4_en_stats->TTOT_prio_7);
+ spin_unlock_bh(&priv->stats_lock);
+
+out:
+ mlx4_free_cmd_mailbox(mdev->dev, mailbox);
+ return err;
+}
+
diff --git a/drivers/net/mlx4/en_port.h b/drivers/net/mlx4/en_port.h
new file mode 100644
index 00000000000..e6477f12beb
--- /dev/null
+++ b/drivers/net/mlx4/en_port.h
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MLX4_EN_PORT_H_
+#define _MLX4_EN_PORT_H_
+
+
+#define SET_PORT_GEN_ALL_VALID 0x7
+#define SET_PORT_PROMISC_SHIFT 31
+
+enum {
+ MLX4_CMD_SET_VLAN_FLTR = 0x47,
+ MLX4_CMD_SET_MCAST_FLTR = 0x48,
+ MLX4_CMD_DUMP_ETH_STATS = 0x49,
+};
+
+struct mlx4_set_port_general_context {
+ u8 reserved[3];
+ u8 flags;
+ u16 reserved2;
+ __be16 mtu;
+ u8 pptx;
+ u8 pfctx;
+ u16 reserved3;
+ u8 pprx;
+ u8 pfcrx;
+ u16 reserved4;
+};
+
+struct mlx4_set_port_rqp_calc_context {
+ __be32 base_qpn;
+ __be32 flags;
+ u8 reserved[3];
+ u8 mac_miss;
+ u8 intra_no_vlan;
+ u8 no_vlan;
+ u8 intra_vlan_miss;
+ u8 vlan_miss;
+ u8 reserved2[3];
+ u8 no_vlan_prio;
+ __be32 promisc;
+ __be32 mcast;
+};
+
+#define VLAN_FLTR_SIZE 128
+struct mlx4_set_vlan_fltr_mbox {
+ __be32 entry[VLAN_FLTR_SIZE];
+};
+
+
+enum {
+ MLX4_MCAST_CONFIG = 0,
+ MLX4_MCAST_DISABLE = 1,
+ MLX4_MCAST_ENABLE = 2,
+};
+
+
+struct mlx4_en_stat_out_mbox {
+ /* Received frames with a length of 64 octets */
+ __be64 R64_prio_0;
+ __be64 R64_prio_1;
+ __be64 R64_prio_2;
+ __be64 R64_prio_3;
+ __be64 R64_prio_4;
+ __be64 R64_prio_5;
+ __be64 R64_prio_6;
+ __be64 R64_prio_7;
+ __be64 R64_novlan;
+ /* Received frames with a length of 127 octets */
+ __be64 R127_prio_0;
+ __be64 R127_prio_1;
+ __be64 R127_prio_2;
+ __be64 R127_prio_3;
+ __be64 R127_prio_4;
+ __be64 R127_prio_5;
+ __be64 R127_prio_6;
+ __be64 R127_prio_7;
+ __be64 R127_novlan;
+ /* Received frames with a length of 255 octets */
+ __be64 R255_prio_0;
+ __be64 R255_prio_1;
+ __be64 R255_prio_2;
+ __be64 R255_prio_3;
+ __be64 R255_prio_4;
+ __be64 R255_prio_5;
+ __be64 R255_prio_6;
+ __be64 R255_prio_7;
+ __be64 R255_novlan;
+ /* Received frames with a length of 511 octets */
+ __be64 R511_prio_0;
+ __be64 R511_prio_1;
+ __be64 R511_prio_2;
+ __be64 R511_prio_3;
+ __be64 R511_prio_4;
+ __be64 R511_prio_5;
+ __be64 R511_prio_6;
+ __be64 R511_prio_7;
+ __be64 R511_novlan;
+ /* Received frames with a length of 1023 octets */
+ __be64 R1023_prio_0;
+ __be64 R1023_prio_1;
+ __be64 R1023_prio_2;
+ __be64 R1023_prio_3;
+ __be64 R1023_prio_4;
+ __be64 R1023_prio_5;
+ __be64 R1023_prio_6;
+ __be64 R1023_prio_7;
+ __be64 R1023_novlan;
+ /* Received frames with a length of 1518 octets */
+ __be64 R1518_prio_0;
+ __be64 R1518_prio_1;
+ __be64 R1518_prio_2;
+ __be64 R1518_prio_3;
+ __be64 R1518_prio_4;
+ __be64 R1518_prio_5;
+ __be64 R1518_prio_6;
+ __be64 R1518_prio_7;
+ __be64 R1518_novlan;
+ /* Received frames with a length of 1522 octets */
+ __be64 R1522_prio_0;
+ __be64 R1522_prio_1;
+ __be64 R1522_prio_2;
+ __be64 R1522_prio_3;
+ __be64 R1522_prio_4;
+ __be64 R1522_prio_5;
+ __be64 R1522_prio_6;
+ __be64 R1522_prio_7;
+ __be64 R1522_novlan;
+ /* Received frames with a length of 1548 octets */
+ __be64 R1548_prio_0;
+ __be64 R1548_prio_1;
+ __be64 R1548_prio_2;
+ __be64 R1548_prio_3;
+ __be64 R1548_prio_4;
+ __be64 R1548_prio_5;
+ __be64 R1548_prio_6;
+ __be64 R1548_prio_7;
+ __be64 R1548_novlan;
+ /* Received frames with a length of 1548 < octets < MTU */
+ __be64 R2MTU_prio_0;
+ __be64 R2MTU_prio_1;
+ __be64 R2MTU_prio_2;
+ __be64 R2MTU_prio_3;
+ __be64 R2MTU_prio_4;
+ __be64 R2MTU_prio_5;
+ __be64 R2MTU_prio_6;
+ __be64 R2MTU_prio_7;
+ __be64 R2MTU_novlan;
+ /* Received frames with a length of MTU< octets and good CRC */
+ __be64 RGIANT_prio_0;
+ __be64 RGIANT_prio_1;
+ __be64 RGIANT_prio_2;
+ __be64 RGIANT_prio_3;
+ __be64 RGIANT_prio_4;
+ __be64 RGIANT_prio_5;
+ __be64 RGIANT_prio_6;
+ __be64 RGIANT_prio_7;
+ __be64 RGIANT_novlan;
+ /* Received broadcast frames with good CRC */
+ __be64 RBCAST_prio_0;
+ __be64 RBCAST_prio_1;
+ __be64 RBCAST_prio_2;
+ __be64 RBCAST_prio_3;
+ __be64 RBCAST_prio_4;
+ __be64 RBCAST_prio_5;
+ __be64 RBCAST_prio_6;
+ __be64 RBCAST_prio_7;
+ __be64 RBCAST_novlan;
+ /* Received multicast frames with good CRC */
+ __be64 MCAST_prio_0;
+ __be64 MCAST_prio_1;
+ __be64 MCAST_prio_2;
+ __be64 MCAST_prio_3;
+ __be64 MCAST_prio_4;
+ __be64 MCAST_prio_5;
+ __be64 MCAST_prio_6;
+ __be64 MCAST_prio_7;
+ __be64 MCAST_novlan;
+ /* Received unicast not short or GIANT frames with good CRC */
+ __be64 RTOTG_prio_0;
+ __be64 RTOTG_prio_1;
+ __be64 RTOTG_prio_2;
+ __be64 RTOTG_prio_3;
+ __be64 RTOTG_prio_4;
+ __be64 RTOTG_prio_5;
+ __be64 RTOTG_prio_6;
+ __be64 RTOTG_prio_7;
+ __be64 RTOTG_novlan;
+
+ /* Count of total octets of received frames, includes framing characters */
+ __be64 RTTLOCT_prio_0;
+ /* Count of total octets of received frames, not including framing
+ characters */
+ __be64 RTTLOCT_NOFRM_prio_0;
+ /* Count of Total number of octets received
+ (only for frames without errors) */
+ __be64 ROCT_prio_0;
+
+ __be64 RTTLOCT_prio_1;
+ __be64 RTTLOCT_NOFRM_prio_1;
+ __be64 ROCT_prio_1;
+
+ __be64 RTTLOCT_prio_2;
+ __be64 RTTLOCT_NOFRM_prio_2;
+ __be64 ROCT_prio_2;
+
+ __be64 RTTLOCT_prio_3;
+ __be64 RTTLOCT_NOFRM_prio_3;
+ __be64 ROCT_prio_3;
+
+ __be64 RTTLOCT_prio_4;
+ __be64 RTTLOCT_NOFRM_prio_4;
+ __be64 ROCT_prio_4;
+
+ __be64 RTTLOCT_prio_5;
+ __be64 RTTLOCT_NOFRM_prio_5;
+ __be64 ROCT_prio_5;
+
+ __be64 RTTLOCT_prio_6;
+ __be64 RTTLOCT_NOFRM_prio_6;
+ __be64 ROCT_prio_6;
+
+ __be64 RTTLOCT_prio_7;
+ __be64 RTTLOCT_NOFRM_prio_7;
+ __be64 ROCT_prio_7;
+
+ __be64 RTTLOCT_novlan;
+ __be64 RTTLOCT_NOFRM_novlan;
+ __be64 ROCT_novlan;
+
+ /* Count of Total received frames including bad frames */
+ __be64 RTOT_prio_0;
+ /* Count of Total number of received frames with 802.1Q encapsulation */
+ __be64 R1Q_prio_0;
+ __be64 reserved1;
+
+ __be64 RTOT_prio_1;
+ __be64 R1Q_prio_1;
+ __be64 reserved2;
+
+ __be64 RTOT_prio_2;
+ __be64 R1Q_prio_2;
+ __be64 reserved3;
+
+ __be64 RTOT_prio_3;
+ __be64 R1Q_prio_3;
+ __be64 reserved4;
+
+ __be64 RTOT_prio_4;
+ __be64 R1Q_prio_4;
+ __be64 reserved5;
+
+ __be64 RTOT_prio_5;
+ __be64 R1Q_prio_5;
+ __be64 reserved6;
+
+ __be64 RTOT_prio_6;
+ __be64 R1Q_prio_6;
+ __be64 reserved7;
+
+ __be64 RTOT_prio_7;
+ __be64 R1Q_prio_7;
+ __be64 reserved8;
+
+ __be64 RTOT_novlan;
+ __be64 R1Q_novlan;
+ __be64 reserved9;
+
+ /* Total number of Successfully Received Control Frames */
+ __be64 RCNTL;
+ __be64 reserved10;
+ __be64 reserved11;
+ __be64 reserved12;
+ /* Count of received frames with a length/type field value between 46
+ (42 for VLANtagged frames) and 1500 (also 1500 for VLAN-tagged frames),
+ inclusive */
+ __be64 RInRangeLengthErr;
+ /* Count of received frames with length/type field between 1501 and 1535
+ decimal, inclusive */
+ __be64 ROutRangeLengthErr;
+ /* Count of received frames that are longer than max allowed size for
+ 802.3 frames (1518/1522) */
+ __be64 RFrmTooLong;
+ /* Count frames received with PCS error */
+ __be64 PCS;
+
+ /* Transmit frames with a length of 64 octets */
+ __be64 T64_prio_0;
+ __be64 T64_prio_1;
+ __be64 T64_prio_2;
+ __be64 T64_prio_3;
+ __be64 T64_prio_4;
+ __be64 T64_prio_5;
+ __be64 T64_prio_6;
+ __be64 T64_prio_7;
+ __be64 T64_novlan;
+ __be64 T64_loopbk;
+ /* Transmit frames with a length of 65 to 127 octets. */
+ __be64 T127_prio_0;
+ __be64 T127_prio_1;
+ __be64 T127_prio_2;
+ __be64 T127_prio_3;
+ __be64 T127_prio_4;
+ __be64 T127_prio_5;
+ __be64 T127_prio_6;
+ __be64 T127_prio_7;
+ __be64 T127_novlan;
+ __be64 T127_loopbk;
+ /* Transmit frames with a length of 128 to 255 octets */
+ __be64 T255_prio_0;
+ __be64 T255_prio_1;
+ __be64 T255_prio_2;
+ __be64 T255_prio_3;
+ __be64 T255_prio_4;
+ __be64 T255_prio_5;
+ __be64 T255_prio_6;
+ __be64 T255_prio_7;
+ __be64 T255_novlan;
+ __be64 T255_loopbk;
+ /* Transmit frames with a length of 256 to 511 octets */
+ __be64 T511_prio_0;
+ __be64 T511_prio_1;
+ __be64 T511_prio_2;
+ __be64 T511_prio_3;
+ __be64 T511_prio_4;
+ __be64 T511_prio_5;
+ __be64 T511_prio_6;
+ __be64 T511_prio_7;
+ __be64 T511_novlan;
+ __be64 T511_loopbk;
+ /* Transmit frames with a length of 512 to 1023 octets */
+ __be64 T1023_prio_0;
+ __be64 T1023_prio_1;
+ __be64 T1023_prio_2;
+ __be64 T1023_prio_3;
+ __be64 T1023_prio_4;
+ __be64 T1023_prio_5;
+ __be64 T1023_prio_6;
+ __be64 T1023_prio_7;
+ __be64 T1023_novlan;
+ __be64 T1023_loopbk;
+ /* Transmit frames with a length of 1024 to 1518 octets */
+ __be64 T1518_prio_0;
+ __be64 T1518_prio_1;
+ __be64 T1518_prio_2;
+ __be64 T1518_prio_3;
+ __be64 T1518_prio_4;
+ __be64 T1518_prio_5;
+ __be64 T1518_prio_6;
+ __be64 T1518_prio_7;
+ __be64 T1518_novlan;
+ __be64 T1518_loopbk;
+ /* Counts transmit frames with a length of 1519 to 1522 bytes */
+ __be64 T1522_prio_0;
+ __be64 T1522_prio_1;
+ __be64 T1522_prio_2;
+ __be64 T1522_prio_3;
+ __be64 T1522_prio_4;
+ __be64 T1522_prio_5;
+ __be64 T1522_prio_6;
+ __be64 T1522_prio_7;
+ __be64 T1522_novlan;
+ __be64 T1522_loopbk;
+ /* Transmit frames with a length of 1523 to 1548 octets */
+ __be64 T1548_prio_0;
+ __be64 T1548_prio_1;
+ __be64 T1548_prio_2;
+ __be64 T1548_prio_3;
+ __be64 T1548_prio_4;
+ __be64 T1548_prio_5;
+ __be64 T1548_prio_6;
+ __be64 T1548_prio_7;
+ __be64 T1548_novlan;
+ __be64 T1548_loopbk;
+ /* Counts transmit frames with a length of 1549 to MTU bytes */
+ __be64 T2MTU_prio_0;
+ __be64 T2MTU_prio_1;
+ __be64 T2MTU_prio_2;
+ __be64 T2MTU_prio_3;
+ __be64 T2MTU_prio_4;
+ __be64 T2MTU_prio_5;
+ __be64 T2MTU_prio_6;
+ __be64 T2MTU_prio_7;
+ __be64 T2MTU_novlan;
+ __be64 T2MTU_loopbk;
+ /* Transmit frames with a length greater than MTU octets and a good CRC. */
+ __be64 TGIANT_prio_0;
+ __be64 TGIANT_prio_1;
+ __be64 TGIANT_prio_2;
+ __be64 TGIANT_prio_3;
+ __be64 TGIANT_prio_4;
+ __be64 TGIANT_prio_5;
+ __be64 TGIANT_prio_6;
+ __be64 TGIANT_prio_7;
+ __be64 TGIANT_novlan;
+ __be64 TGIANT_loopbk;
+ /* Transmit broadcast frames with a good CRC */
+ __be64 TBCAST_prio_0;
+ __be64 TBCAST_prio_1;
+ __be64 TBCAST_prio_2;
+ __be64 TBCAST_prio_3;
+ __be64 TBCAST_prio_4;
+ __be64 TBCAST_prio_5;
+ __be64 TBCAST_prio_6;
+ __be64 TBCAST_prio_7;
+ __be64 TBCAST_novlan;
+ __be64 TBCAST_loopbk;
+ /* Transmit multicast frames with a good CRC */
+ __be64 TMCAST_prio_0;
+ __be64 TMCAST_prio_1;
+ __be64 TMCAST_prio_2;
+ __be64 TMCAST_prio_3;
+ __be64 TMCAST_prio_4;
+ __be64 TMCAST_prio_5;
+ __be64 TMCAST_prio_6;
+ __be64 TMCAST_prio_7;
+ __be64 TMCAST_novlan;
+ __be64 TMCAST_loopbk;
+ /* Transmit good frames that are neither broadcast nor multicast */
+ __be64 TTOTG_prio_0;
+ __be64 TTOTG_prio_1;
+ __be64 TTOTG_prio_2;
+ __be64 TTOTG_prio_3;
+ __be64 TTOTG_prio_4;
+ __be64 TTOTG_prio_5;
+ __be64 TTOTG_prio_6;
+ __be64 TTOTG_prio_7;
+ __be64 TTOTG_novlan;
+ __be64 TTOTG_loopbk;
+
+ /* total octets of transmitted frames, including framing characters */
+ __be64 TTTLOCT_prio_0;
+ /* total octets of transmitted frames, not including framing characters */
+ __be64 TTTLOCT_NOFRM_prio_0;
+ /* ifOutOctets */
+ __be64 TOCT_prio_0;
+
+ __be64 TTTLOCT_prio_1;
+ __be64 TTTLOCT_NOFRM_prio_1;
+ __be64 TOCT_prio_1;
+
+ __be64 TTTLOCT_prio_2;
+ __be64 TTTLOCT_NOFRM_prio_2;
+ __be64 TOCT_prio_2;
+
+ __be64 TTTLOCT_prio_3;
+ __be64 TTTLOCT_NOFRM_prio_3;
+ __be64 TOCT_prio_3;
+
+ __be64 TTTLOCT_prio_4;
+ __be64 TTTLOCT_NOFRM_prio_4;
+ __be64 TOCT_prio_4;
+
+ __be64 TTTLOCT_prio_5;
+ __be64 TTTLOCT_NOFRM_prio_5;
+ __be64 TOCT_prio_5;
+
+ __be64 TTTLOCT_prio_6;
+ __be64 TTTLOCT_NOFRM_prio_6;
+ __be64 TOCT_prio_6;
+
+ __be64 TTTLOCT_prio_7;
+ __be64 TTTLOCT_NOFRM_prio_7;
+ __be64 TOCT_prio_7;
+
+ __be64 TTTLOCT_novlan;
+ __be64 TTTLOCT_NOFRM_novlan;
+ __be64 TOCT_novlan;
+
+ __be64 TTTLOCT_loopbk;
+ __be64 TTTLOCT_NOFRM_loopbk;
+ __be64 TOCT_loopbk;
+
+ /* Total frames transmitted with a good CRC that are not aborted */
+ __be64 TTOT_prio_0;
+ /* Total number of frames transmitted with 802.1Q encapsulation */
+ __be64 T1Q_prio_0;
+ __be64 reserved13;
+
+ __be64 TTOT_prio_1;
+ __be64 T1Q_prio_1;
+ __be64 reserved14;
+
+ __be64 TTOT_prio_2;
+ __be64 T1Q_prio_2;
+ __be64 reserved15;
+
+ __be64 TTOT_prio_3;
+ __be64 T1Q_prio_3;
+ __be64 reserved16;
+
+ __be64 TTOT_prio_4;
+ __be64 T1Q_prio_4;
+ __be64 reserved17;
+
+ __be64 TTOT_prio_5;
+ __be64 T1Q_prio_5;
+ __be64 reserved18;
+
+ __be64 TTOT_prio_6;
+ __be64 T1Q_prio_6;
+ __be64 reserved19;
+
+ __be64 TTOT_prio_7;
+ __be64 T1Q_prio_7;
+ __be64 reserved20;
+
+ __be64 TTOT_novlan;
+ __be64 T1Q_novlan;
+ __be64 reserved21;
+
+ __be64 TTOT_loopbk;
+ __be64 T1Q_loopbk;
+ __be64 reserved22;
+
+ /* Received frames with a length greater than MTU octets and a bad CRC */
+ __be32 RJBBR;
+ /* Received frames with a bad CRC that are not runts, jabbers,
+ or alignment errors */
+ __be32 RCRC;
+ /* Received frames with SFD with a length of less than 64 octets and a
+ bad CRC */
+ __be32 RRUNT;
+ /* Received frames with a length less than 64 octets and a good CRC */
+ __be32 RSHORT;
+ /* Total Number of Received Packets Dropped */
+ __be32 RDROP;
+ /* Drop due to overflow */
+ __be32 RdropOvflw;
+ /* Drop due to overflow */
+ __be32 RdropLength;
+ /* Total of good frames. Does not include frames received with
+ frame-too-long, FCS, or length errors */
+ __be32 RTOTFRMS;
+ /* Total dropped Xmited packets */
+ __be32 TDROP;
+};
+
+
+#endif
diff --git a/drivers/net/mlx4/en_resources.c b/drivers/net/mlx4/en_resources.c
new file mode 100644
index 00000000000..a0545209e50
--- /dev/null
+++ b/drivers/net/mlx4/en_resources.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/mlx4/qp.h>
+
+#include "mlx4_en.h"
+
+void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
+ int is_tx, int rss, int qpn, int cqn, int srqn,
+ struct mlx4_qp_context *context)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ memset(context, 0, sizeof *context);
+ context->flags = cpu_to_be32(7 << 16 | rss << 13);
+ context->pd = cpu_to_be32(mdev->priv_pdn);
+ context->mtu_msgmax = 0xff;
+ context->rq_size_stride = 0;
+ if (is_tx)
+ context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4);
+ else
+ context->sq_size_stride = 1;
+ context->usr_page = cpu_to_be32(mdev->priv_uar.index);
+ context->local_qpn = cpu_to_be32(qpn);
+ context->pri_path.ackto = 1 & 0x07;
+ context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6;
+ context->pri_path.counter_index = 0xff;
+ context->cqn_send = cpu_to_be32(cqn);
+ context->cqn_recv = cpu_to_be32(cqn);
+ context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2);
+ if (!rss)
+ context->srqn = cpu_to_be32(MLX4_EN_USE_SRQ | srqn);
+}
+
+
+int mlx4_en_map_buffer(struct mlx4_buf *buf)
+{
+ struct page **pages;
+ int i;
+
+ if (BITS_PER_LONG == 64 || buf->nbufs == 1)
+ return 0;
+
+ pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL);
+ if (!pages)
+ return -ENOMEM;
+
+ for (i = 0; i < buf->nbufs; ++i)
+ pages[i] = virt_to_page(buf->page_list[i].buf);
+
+ buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL);
+ kfree(pages);
+ if (!buf->direct.buf)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx4_en_unmap_buffer(struct mlx4_buf *buf)
+{
+ if (BITS_PER_LONG == 64 || buf->nbufs == 1)
+ return;
+
+ vunmap(buf->direct.buf);
+}
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c
new file mode 100644
index 00000000000..6232227f56c
--- /dev/null
+++ b/drivers/net/mlx4/en_rx.c
@@ -0,0 +1,1080 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/mlx4/cq.h>
+#include <linux/mlx4/qp.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/vmalloc.h>
+
+#include "mlx4_en.h"
+
+static void *get_wqe(struct mlx4_en_rx_ring *ring, int n)
+{
+ int offset = n << ring->srq.wqe_shift;
+ return ring->buf + offset;
+}
+
+static void mlx4_en_srq_event(struct mlx4_srq *srq, enum mlx4_event type)
+{
+ return;
+}
+
+static int mlx4_en_get_frag_header(struct skb_frag_struct *frags, void **mac_hdr,
+ void **ip_hdr, void **tcpudp_hdr,
+ u64 *hdr_flags, void *priv)
+{
+ *mac_hdr = page_address(frags->page) + frags->page_offset;
+ *ip_hdr = *mac_hdr + ETH_HLEN;
+ *tcpudp_hdr = (struct tcphdr *)(*ip_hdr + sizeof(struct iphdr));
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+
+ return 0;
+}
+
+static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_desc *rx_desc,
+ struct skb_frag_struct *skb_frags,
+ struct mlx4_en_rx_alloc *ring_alloc,
+ int i)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_frag_info *frag_info = &priv->frag_info[i];
+ struct mlx4_en_rx_alloc *page_alloc = &ring_alloc[i];
+ struct page *page;
+ dma_addr_t dma;
+
+ if (page_alloc->offset == frag_info->last_offset) {
+ /* Allocate new page */
+ page = alloc_pages(GFP_ATOMIC | __GFP_COMP, MLX4_EN_ALLOC_ORDER);
+ if (!page)
+ return -ENOMEM;
+
+ skb_frags[i].page = page_alloc->page;
+ skb_frags[i].page_offset = page_alloc->offset;
+ page_alloc->page = page;
+ page_alloc->offset = frag_info->frag_align;
+ } else {
+ page = page_alloc->page;
+ get_page(page);
+
+ skb_frags[i].page = page;
+ skb_frags[i].page_offset = page_alloc->offset;
+ page_alloc->offset += frag_info->frag_stride;
+ }
+ dma = pci_map_single(mdev->pdev, page_address(skb_frags[i].page) +
+ skb_frags[i].page_offset, frag_info->frag_size,
+ PCI_DMA_FROMDEVICE);
+ rx_desc->data[i].addr = cpu_to_be64(dma);
+ return 0;
+}
+
+static int mlx4_en_init_allocator(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring)
+{
+ struct mlx4_en_rx_alloc *page_alloc;
+ int i;
+
+ for (i = 0; i < priv->num_frags; i++) {
+ page_alloc = &ring->page_alloc[i];
+ page_alloc->page = alloc_pages(GFP_ATOMIC | __GFP_COMP,
+ MLX4_EN_ALLOC_ORDER);
+ if (!page_alloc->page)
+ goto out;
+
+ page_alloc->offset = priv->frag_info[i].frag_align;
+ mlx4_dbg(DRV, priv, "Initialized allocator:%d with page:%p\n",
+ i, page_alloc->page);
+ }
+ return 0;
+
+out:
+ while (i--) {
+ page_alloc = &ring->page_alloc[i];
+ put_page(page_alloc->page);
+ page_alloc->page = NULL;
+ }
+ return -ENOMEM;
+}
+
+static void mlx4_en_destroy_allocator(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring)
+{
+ struct mlx4_en_rx_alloc *page_alloc;
+ int i;
+
+ for (i = 0; i < priv->num_frags; i++) {
+ page_alloc = &ring->page_alloc[i];
+ mlx4_dbg(DRV, priv, "Freeing allocator:%d count:%d\n",
+ i, page_count(page_alloc->page));
+
+ put_page(page_alloc->page);
+ page_alloc->page = NULL;
+ }
+}
+
+
+static void mlx4_en_init_rx_desc(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring, int index)
+{
+ struct mlx4_en_rx_desc *rx_desc = ring->buf + ring->stride * index;
+ struct skb_frag_struct *skb_frags = ring->rx_info +
+ (index << priv->log_rx_info);
+ int possible_frags;
+ int i;
+
+ /* Pre-link descriptor */
+ rx_desc->next.next_wqe_index = cpu_to_be16((index + 1) & ring->size_mask);
+
+ /* Set size and memtype fields */
+ for (i = 0; i < priv->num_frags; i++) {
+ skb_frags[i].size = priv->frag_info[i].frag_size;
+ rx_desc->data[i].byte_count =
+ cpu_to_be32(priv->frag_info[i].frag_size);
+ rx_desc->data[i].lkey = cpu_to_be32(priv->mdev->mr.key);
+ }
+
+ /* If the number of used fragments does not fill up the ring stride,
+ * remaining (unused) fragments must be padded with null address/size
+ * and a special memory key */
+ possible_frags = (ring->stride - sizeof(struct mlx4_en_rx_desc)) / DS_SIZE;
+ for (i = priv->num_frags; i < possible_frags; i++) {
+ rx_desc->data[i].byte_count = 0;
+ rx_desc->data[i].lkey = cpu_to_be32(MLX4_EN_MEMTYPE_PAD);
+ rx_desc->data[i].addr = 0;
+ }
+}
+
+
+static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring, int index)
+{
+ struct mlx4_en_rx_desc *rx_desc = ring->buf + (index * ring->stride);
+ struct skb_frag_struct *skb_frags = ring->rx_info +
+ (index << priv->log_rx_info);
+ int i;
+
+ for (i = 0; i < priv->num_frags; i++)
+ if (mlx4_en_alloc_frag(priv, rx_desc, skb_frags, ring->page_alloc, i))
+ goto err;
+
+ return 0;
+
+err:
+ while (i--)
+ put_page(skb_frags[i].page);
+ return -ENOMEM;
+}
+
+static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring)
+{
+ *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff);
+}
+
+static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_rx_ring *ring;
+ int ring_ind;
+ int buf_ind;
+
+ for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) {
+ for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
+ ring = &priv->rx_ring[ring_ind];
+
+ if (mlx4_en_prepare_rx_desc(priv, ring,
+ ring->actual_size)) {
+ if (ring->actual_size < MLX4_EN_MIN_RX_SIZE) {
+ mlx4_err(mdev, "Failed to allocate "
+ "enough rx buffers\n");
+ return -ENOMEM;
+ } else {
+ if (netif_msg_rx_err(priv))
+ mlx4_warn(mdev,
+ "Only %d buffers allocated\n",
+ ring->actual_size);
+ goto out;
+ }
+ }
+ ring->actual_size++;
+ ring->prod++;
+ }
+ }
+out:
+ return 0;
+}
+
+static int mlx4_en_fill_rx_buf(struct net_device *dev,
+ struct mlx4_en_rx_ring *ring)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int num = 0;
+ int err;
+
+ while ((u32) (ring->prod - ring->cons) < ring->actual_size) {
+ err = mlx4_en_prepare_rx_desc(priv, ring, ring->prod &
+ ring->size_mask);
+ if (err) {
+ if (netif_msg_rx_err(priv))
+ mlx4_warn(priv->mdev,
+ "Failed preparing rx descriptor\n");
+ priv->port_stats.rx_alloc_failed++;
+ break;
+ }
+ ++num;
+ ++ring->prod;
+ }
+ if ((u32) (ring->prod - ring->cons) == ring->size)
+ ring->full = 1;
+
+ return num;
+}
+
+static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct skb_frag_struct *skb_frags;
+ struct mlx4_en_rx_desc *rx_desc;
+ dma_addr_t dma;
+ int index;
+ int nr;
+
+ mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n",
+ ring->cons, ring->prod);
+
+ /* Unmap and free Rx buffers */
+ BUG_ON((u32) (ring->prod - ring->cons) > ring->size);
+ while (ring->cons != ring->prod) {
+ index = ring->cons & ring->size_mask;
+ rx_desc = ring->buf + (index << ring->log_stride);
+ skb_frags = ring->rx_info + (index << priv->log_rx_info);
+ mlx4_dbg(DRV, priv, "Processing descriptor:%d\n", index);
+
+ for (nr = 0; nr < priv->num_frags; nr++) {
+ mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr);
+ dma = be64_to_cpu(rx_desc->data[nr].addr);
+
+ mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma);
+ pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size,
+ PCI_DMA_FROMDEVICE);
+ put_page(skb_frags[nr].page);
+ }
+ ++ring->cons;
+ }
+}
+
+
+void mlx4_en_rx_refill(struct work_struct *work)
+{
+ struct delayed_work *delay = container_of(work, struct delayed_work, work);
+ struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv,
+ refill_task);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct net_device *dev = priv->dev;
+ struct mlx4_en_rx_ring *ring;
+ int need_refill = 0;
+ int i;
+
+ mutex_lock(&mdev->state_lock);
+ if (!mdev->device_up || !priv->port_up)
+ goto out;
+
+ /* We only get here if there are no receive buffers, so we can't race
+ * with Rx interrupts while filling buffers */
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ ring = &priv->rx_ring[i];
+ if (ring->need_refill) {
+ if (mlx4_en_fill_rx_buf(dev, ring)) {
+ ring->need_refill = 0;
+ mlx4_en_update_rx_prod_db(ring);
+ } else
+ need_refill = 1;
+ }
+ }
+ if (need_refill)
+ queue_delayed_work(mdev->workqueue, &priv->refill_task, HZ);
+
+out:
+ mutex_unlock(&mdev->state_lock);
+}
+
+
+int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring, u32 size, u16 stride)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+ int tmp;
+
+ /* Sanity check SRQ size before proceeding */
+ if (size >= mdev->dev->caps.max_srq_wqes)
+ return -EINVAL;
+
+ ring->prod = 0;
+ ring->cons = 0;
+ ring->size = size;
+ ring->size_mask = size - 1;
+ ring->stride = stride;
+ ring->log_stride = ffs(ring->stride) - 1;
+ ring->buf_size = ring->size * ring->stride;
+
+ tmp = size * roundup_pow_of_two(MLX4_EN_MAX_RX_FRAGS *
+ sizeof(struct skb_frag_struct));
+ ring->rx_info = vmalloc(tmp);
+ if (!ring->rx_info) {
+ mlx4_err(mdev, "Failed allocating rx_info ring\n");
+ return -ENOMEM;
+ }
+ mlx4_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n",
+ ring->rx_info, tmp);
+
+ err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres,
+ ring->buf_size, 2 * PAGE_SIZE);
+ if (err)
+ goto err_ring;
+
+ err = mlx4_en_map_buffer(&ring->wqres.buf);
+ if (err) {
+ mlx4_err(mdev, "Failed to map RX buffer\n");
+ goto err_hwq;
+ }
+ ring->buf = ring->wqres.buf.direct.buf;
+
+ /* Configure lro mngr */
+ memset(&ring->lro, 0, sizeof(struct net_lro_mgr));
+ ring->lro.dev = priv->dev;
+ ring->lro.features = LRO_F_NAPI;
+ ring->lro.frag_align_pad = NET_IP_ALIGN;
+ ring->lro.ip_summed = CHECKSUM_UNNECESSARY;
+ ring->lro.ip_summed_aggr = CHECKSUM_UNNECESSARY;
+ ring->lro.max_desc = mdev->profile.num_lro;
+ ring->lro.max_aggr = MAX_SKB_FRAGS;
+ ring->lro.lro_arr = kzalloc(mdev->profile.num_lro *
+ sizeof(struct net_lro_desc),
+ GFP_KERNEL);
+ if (!ring->lro.lro_arr) {
+ mlx4_err(mdev, "Failed to allocate lro array\n");
+ goto err_map;
+ }
+ ring->lro.get_frag_header = mlx4_en_get_frag_header;
+
+ return 0;
+
+err_map:
+ mlx4_en_unmap_buffer(&ring->wqres.buf);
+err_hwq:
+ mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
+err_ring:
+ vfree(ring->rx_info);
+ ring->rx_info = NULL;
+ return err;
+}
+
+int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_wqe_srq_next_seg *next;
+ struct mlx4_en_rx_ring *ring;
+ int i;
+ int ring_ind;
+ int err;
+ int stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
+ DS_SIZE * priv->num_frags);
+ int max_gs = (stride - sizeof(struct mlx4_wqe_srq_next_seg)) / DS_SIZE;
+
+ for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
+ ring = &priv->rx_ring[ring_ind];
+
+ ring->prod = 0;
+ ring->cons = 0;
+ ring->actual_size = 0;
+ ring->cqn = priv->rx_cq[ring_ind].mcq.cqn;
+
+ ring->stride = stride;
+ ring->log_stride = ffs(ring->stride) - 1;
+ ring->buf_size = ring->size * ring->stride;
+
+ memset(ring->buf, 0, ring->buf_size);
+ mlx4_en_update_rx_prod_db(ring);
+
+ /* Initailize all descriptors */
+ for (i = 0; i < ring->size; i++)
+ mlx4_en_init_rx_desc(priv, ring, i);
+
+ /* Initialize page allocators */
+ err = mlx4_en_init_allocator(priv, ring);
+ if (err) {
+ mlx4_err(mdev, "Failed initializing ring allocator\n");
+ goto err_allocator;
+ }
+
+ /* Fill Rx buffers */
+ ring->full = 0;
+ }
+ if (mlx4_en_fill_rx_buffers(priv))
+ goto err_buffers;
+
+ for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
+ ring = &priv->rx_ring[ring_ind];
+
+ mlx4_en_update_rx_prod_db(ring);
+
+ /* Configure SRQ representing the ring */
+ ring->srq.max = ring->size;
+ ring->srq.max_gs = max_gs;
+ ring->srq.wqe_shift = ilog2(ring->stride);
+
+ for (i = 0; i < ring->srq.max; ++i) {
+ next = get_wqe(ring, i);
+ next->next_wqe_index =
+ cpu_to_be16((i + 1) & (ring->srq.max - 1));
+ }
+
+ err = mlx4_srq_alloc(mdev->dev, mdev->priv_pdn, &ring->wqres.mtt,
+ ring->wqres.db.dma, &ring->srq);
+ if (err){
+ mlx4_err(mdev, "Failed to allocate srq\n");
+ goto err_srq;
+ }
+ ring->srq.event = mlx4_en_srq_event;
+ }
+
+ return 0;
+
+err_srq:
+ while (ring_ind >= 0) {
+ ring = &priv->rx_ring[ring_ind];
+ mlx4_srq_free(mdev->dev, &ring->srq);
+ ring_ind--;
+ }
+
+err_buffers:
+ for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++)
+ mlx4_en_free_rx_buf(priv, &priv->rx_ring[ring_ind]);
+
+ ring_ind = priv->rx_ring_num - 1;
+err_allocator:
+ while (ring_ind >= 0) {
+ mlx4_en_destroy_allocator(priv, &priv->rx_ring[ring_ind]);
+ ring_ind--;
+ }
+ return err;
+}
+
+void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ kfree(ring->lro.lro_arr);
+ mlx4_en_unmap_buffer(&ring->wqres.buf);
+ mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
+ vfree(ring->rx_info);
+ ring->rx_info = NULL;
+}
+
+void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ mlx4_srq_free(mdev->dev, &ring->srq);
+ mlx4_en_free_rx_buf(priv, ring);
+ mlx4_en_destroy_allocator(priv, ring);
+}
+
+
+/* Unmap a completed descriptor and free unused pages */
+static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_desc *rx_desc,
+ struct skb_frag_struct *skb_frags,
+ struct skb_frag_struct *skb_frags_rx,
+ struct mlx4_en_rx_alloc *page_alloc,
+ int length)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_frag_info *frag_info;
+ int nr;
+ dma_addr_t dma;
+
+ /* Collect used fragments while replacing them in the HW descirptors */
+ for (nr = 0; nr < priv->num_frags; nr++) {
+ frag_info = &priv->frag_info[nr];
+ if (length <= frag_info->frag_prefix_size)
+ break;
+
+ /* Save page reference in skb */
+ skb_frags_rx[nr].page = skb_frags[nr].page;
+ skb_frags_rx[nr].size = skb_frags[nr].size;
+ skb_frags_rx[nr].page_offset = skb_frags[nr].page_offset;
+ dma = be64_to_cpu(rx_desc->data[nr].addr);
+
+ /* Allocate a replacement page */
+ if (mlx4_en_alloc_frag(priv, rx_desc, skb_frags, page_alloc, nr))
+ goto fail;
+
+ /* Unmap buffer */
+ pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size,
+ PCI_DMA_FROMDEVICE);
+ }
+ /* Adjust size of last fragment to match actual length */
+ skb_frags_rx[nr - 1].size = length -
+ priv->frag_info[nr - 1].frag_prefix_size;
+ return nr;
+
+fail:
+ /* Drop all accumulated fragments (which have already been replaced in
+ * the descriptor) of this packet; remaining fragments are reused... */
+ while (nr > 0) {
+ nr--;
+ put_page(skb_frags_rx[nr].page);
+ }
+ return 0;
+}
+
+
+static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_desc *rx_desc,
+ struct skb_frag_struct *skb_frags,
+ struct mlx4_en_rx_alloc *page_alloc,
+ unsigned int length)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct sk_buff *skb;
+ void *va;
+ int used_frags;
+ dma_addr_t dma;
+
+ skb = dev_alloc_skb(SMALL_PACKET_SIZE + NET_IP_ALIGN);
+ if (!skb) {
+ mlx4_dbg(RX_ERR, priv, "Failed allocating skb\n");
+ return NULL;
+ }
+ skb->dev = priv->dev;
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb->len = length;
+ skb->truesize = length + sizeof(struct sk_buff);
+
+ /* Get pointer to first fragment so we could copy the headers into the
+ * (linear part of the) skb */
+ va = page_address(skb_frags[0].page) + skb_frags[0].page_offset;
+
+ if (length <= SMALL_PACKET_SIZE) {
+ /* We are copying all relevant data to the skb - temporarily
+ * synch buffers for the copy */
+ dma = be64_to_cpu(rx_desc->data[0].addr);
+ dma_sync_single_range_for_cpu(&mdev->pdev->dev, dma, 0,
+ length, DMA_FROM_DEVICE);
+ skb_copy_to_linear_data(skb, va, length);
+ dma_sync_single_range_for_device(&mdev->pdev->dev, dma, 0,
+ length, DMA_FROM_DEVICE);
+ skb->tail += length;
+ } else {
+
+ /* Move relevant fragments to skb */
+ used_frags = mlx4_en_complete_rx_desc(priv, rx_desc, skb_frags,
+ skb_shinfo(skb)->frags,
+ page_alloc, length);
+ skb_shinfo(skb)->nr_frags = used_frags;
+
+ /* Copy headers into the skb linear buffer */
+ memcpy(skb->data, va, HEADER_COPY_SIZE);
+ skb->tail += HEADER_COPY_SIZE;
+
+ /* Skip headers in first fragment */
+ skb_shinfo(skb)->frags[0].page_offset += HEADER_COPY_SIZE;
+
+ /* Adjust size of first fragment */
+ skb_shinfo(skb)->frags[0].size -= HEADER_COPY_SIZE;
+ skb->data_len = length - HEADER_COPY_SIZE;
+ }
+ return skb;
+}
+
+static void mlx4_en_copy_desc(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring,
+ int from, int to, int num)
+{
+ struct skb_frag_struct *skb_frags_from;
+ struct skb_frag_struct *skb_frags_to;
+ struct mlx4_en_rx_desc *rx_desc_from;
+ struct mlx4_en_rx_desc *rx_desc_to;
+ int from_index, to_index;
+ int nr, i;
+
+ for (i = 0; i < num; i++) {
+ from_index = (from + i) & ring->size_mask;
+ to_index = (to + i) & ring->size_mask;
+ skb_frags_from = ring->rx_info + (from_index << priv->log_rx_info);
+ skb_frags_to = ring->rx_info + (to_index << priv->log_rx_info);
+ rx_desc_from = ring->buf + (from_index << ring->log_stride);
+ rx_desc_to = ring->buf + (to_index << ring->log_stride);
+
+ for (nr = 0; nr < priv->num_frags; nr++) {
+ skb_frags_to[nr].page = skb_frags_from[nr].page;
+ skb_frags_to[nr].page_offset = skb_frags_from[nr].page_offset;
+ rx_desc_to->data[nr].addr = rx_desc_from->data[nr].addr;
+ }
+ }
+}
+
+
+int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_cqe *cqe;
+ struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring];
+ struct skb_frag_struct *skb_frags;
+ struct skb_frag_struct lro_frags[MLX4_EN_MAX_RX_FRAGS];
+ struct mlx4_en_rx_desc *rx_desc;
+ struct sk_buff *skb;
+ int index;
+ int nr;
+ unsigned int length;
+ int polled = 0;
+ int ip_summed;
+
+ if (!priv->port_up)
+ return 0;
+
+ /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx
+ * descriptor offset can be deduced from the CQE index instead of
+ * reading 'cqe->index' */
+ index = cq->mcq.cons_index & ring->size_mask;
+ cqe = &cq->buf[index];
+
+ /* Process all completed CQEs */
+ while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK,
+ cq->mcq.cons_index & cq->size)) {
+
+ skb_frags = ring->rx_info + (index << priv->log_rx_info);
+ rx_desc = ring->buf + (index << ring->log_stride);
+
+ /*
+ * make sure we read the CQE after we read the ownership bit
+ */
+ rmb();
+
+ /* Drop packet on bad receive or bad checksum */
+ if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) ==
+ MLX4_CQE_OPCODE_ERROR)) {
+ mlx4_err(mdev, "CQE completed in error - vendor "
+ "syndrom:%d syndrom:%d\n",
+ ((struct mlx4_err_cqe *) cqe)->vendor_err_syndrome,
+ ((struct mlx4_err_cqe *) cqe)->syndrome);
+ goto next;
+ }
+ if (unlikely(cqe->badfcs_enc & MLX4_CQE_BAD_FCS)) {
+ mlx4_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n");
+ goto next;
+ }
+
+ /*
+ * Packet is OK - process it.
+ */
+ length = be32_to_cpu(cqe->byte_cnt);
+ ring->bytes += length;
+ ring->packets++;
+
+ if (likely(priv->rx_csum)) {
+ if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
+ (cqe->checksum == cpu_to_be16(0xffff))) {
+ priv->port_stats.rx_chksum_good++;
+ /* This packet is eligible for LRO if it is:
+ * - DIX Ethernet (type interpretation)
+ * - TCP/IP (v4)
+ * - without IP options
+ * - not an IP fragment */
+ if (mlx4_en_can_lro(cqe->status) &&
+ dev->features & NETIF_F_LRO) {
+
+ nr = mlx4_en_complete_rx_desc(
+ priv, rx_desc,
+ skb_frags, lro_frags,
+ ring->page_alloc, length);
+ if (!nr)
+ goto next;
+
+ if (priv->vlgrp && (cqe->vlan_my_qpn &
+ cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK))) {
+ lro_vlan_hwaccel_receive_frags(
+ &ring->lro, lro_frags,
+ length, length,
+ priv->vlgrp,
+ be16_to_cpu(cqe->sl_vid),
+ NULL, 0);
+ } else
+ lro_receive_frags(&ring->lro,
+ lro_frags,
+ length,
+ length,
+ NULL, 0);
+
+ goto next;
+ }
+
+ /* LRO not possible, complete processing here */
+ ip_summed = CHECKSUM_UNNECESSARY;
+ INC_PERF_COUNTER(priv->pstats.lro_misses);
+ } else {
+ ip_summed = CHECKSUM_NONE;
+ priv->port_stats.rx_chksum_none++;
+ }
+ } else {
+ ip_summed = CHECKSUM_NONE;
+ priv->port_stats.rx_chksum_none++;
+ }
+
+ skb = mlx4_en_rx_skb(priv, rx_desc, skb_frags,
+ ring->page_alloc, length);
+ if (!skb) {
+ priv->stats.rx_dropped++;
+ goto next;
+ }
+
+ skb->ip_summed = ip_summed;
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* Push it up the stack */
+ if (priv->vlgrp && (be32_to_cpu(cqe->vlan_my_qpn) &
+ MLX4_CQE_VLAN_PRESENT_MASK)) {
+ vlan_hwaccel_receive_skb(skb, priv->vlgrp,
+ be16_to_cpu(cqe->sl_vid));
+ } else
+ netif_receive_skb(skb);
+
+ dev->last_rx = jiffies;
+
+next:
+ ++cq->mcq.cons_index;
+ index = (cq->mcq.cons_index) & ring->size_mask;
+ cqe = &cq->buf[index];
+ if (++polled == budget) {
+ /* We are here because we reached the NAPI budget -
+ * flush only pending LRO sessions */
+ lro_flush_all(&ring->lro);
+ goto out;
+ }
+ }
+
+ /* If CQ is empty flush all LRO sessions unconditionally */
+ lro_flush_all(&ring->lro);
+
+out:
+ AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled);
+ mlx4_cq_set_ci(&cq->mcq);
+ wmb(); /* ensure HW sees CQ consumer before we post new buffers */
+ ring->cons = cq->mcq.cons_index;
+ ring->prod += polled; /* Polled descriptors were realocated in place */
+ if (unlikely(!ring->full)) {
+ mlx4_en_copy_desc(priv, ring, ring->cons - polled,
+ ring->prod - polled, polled);
+ mlx4_en_fill_rx_buf(dev, ring);
+ }
+ mlx4_en_update_rx_prod_db(ring);
+ return polled;
+}
+
+
+void mlx4_en_rx_irq(struct mlx4_cq *mcq)
+{
+ struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq);
+ struct mlx4_en_priv *priv = netdev_priv(cq->dev);
+
+ if (priv->port_up)
+ netif_rx_schedule(cq->dev, &cq->napi);
+ else
+ mlx4_en_arm_cq(priv, cq);
+}
+
+/* Rx CQ polling - called by NAPI */
+int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget)
+{
+ struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi);
+ struct net_device *dev = cq->dev;
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int done;
+
+ done = mlx4_en_process_rx_cq(dev, cq, budget);
+
+ /* If we used up all the quota - we're probably not done yet... */
+ if (done == budget)
+ INC_PERF_COUNTER(priv->pstats.napi_quota);
+ else {
+ /* Done for now */
+ netif_rx_complete(dev, napi);
+ mlx4_en_arm_cq(priv, cq);
+ }
+ return done;
+}
+
+
+/* Calculate the last offset position that accomodates a full fragment
+ * (assuming fagment size = stride-align) */
+static int mlx4_en_last_alloc_offset(struct mlx4_en_priv *priv, u16 stride, u16 align)
+{
+ u16 res = MLX4_EN_ALLOC_SIZE % stride;
+ u16 offset = MLX4_EN_ALLOC_SIZE - stride - res + align;
+
+ mlx4_dbg(DRV, priv, "Calculated last offset for stride:%d align:%d "
+ "res:%d offset:%d\n", stride, align, res, offset);
+ return offset;
+}
+
+
+static int frag_sizes[] = {
+ FRAG_SZ0,
+ FRAG_SZ1,
+ FRAG_SZ2,
+ FRAG_SZ3
+};
+
+void mlx4_en_calc_rx_buf(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int eff_mtu = dev->mtu + ETH_HLEN + VLAN_HLEN + ETH_LLC_SNAP_SIZE;
+ int buf_size = 0;
+ int i = 0;
+
+ while (buf_size < eff_mtu) {
+ priv->frag_info[i].frag_size =
+ (eff_mtu > buf_size + frag_sizes[i]) ?
+ frag_sizes[i] : eff_mtu - buf_size;
+ priv->frag_info[i].frag_prefix_size = buf_size;
+ if (!i) {
+ priv->frag_info[i].frag_align = NET_IP_ALIGN;
+ priv->frag_info[i].frag_stride =
+ ALIGN(frag_sizes[i] + NET_IP_ALIGN, SMP_CACHE_BYTES);
+ } else {
+ priv->frag_info[i].frag_align = 0;
+ priv->frag_info[i].frag_stride =
+ ALIGN(frag_sizes[i], SMP_CACHE_BYTES);
+ }
+ priv->frag_info[i].last_offset = mlx4_en_last_alloc_offset(
+ priv, priv->frag_info[i].frag_stride,
+ priv->frag_info[i].frag_align);
+ buf_size += priv->frag_info[i].frag_size;
+ i++;
+ }
+
+ priv->num_frags = i;
+ priv->rx_skb_size = eff_mtu;
+ priv->log_rx_info = ROUNDUP_LOG2(i * sizeof(struct skb_frag_struct));
+
+ mlx4_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d "
+ "num_frags:%d):\n", eff_mtu, priv->num_frags);
+ for (i = 0; i < priv->num_frags; i++) {
+ mlx4_dbg(DRV, priv, " frag:%d - size:%d prefix:%d align:%d "
+ "stride:%d last_offset:%d\n", i,
+ priv->frag_info[i].frag_size,
+ priv->frag_info[i].frag_prefix_size,
+ priv->frag_info[i].frag_align,
+ priv->frag_info[i].frag_stride,
+ priv->frag_info[i].last_offset);
+ }
+}
+
+/* RSS related functions */
+
+/* Calculate rss size and map each entry in rss table to rx ring */
+void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv,
+ struct mlx4_en_rss_map *rss_map,
+ int num_entries, int num_rings)
+{
+ int i;
+
+ rss_map->size = roundup_pow_of_two(num_entries);
+ mlx4_dbg(DRV, priv, "Setting default RSS map of %d entires\n",
+ rss_map->size);
+
+ for (i = 0; i < rss_map->size; i++) {
+ rss_map->map[i] = i % num_rings;
+ mlx4_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]);
+ }
+}
+
+static void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event)
+{
+ return;
+}
+
+
+static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv,
+ int qpn, int srqn, int cqn,
+ enum mlx4_qp_state *state,
+ struct mlx4_qp *qp)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_qp_context *context;
+ int err = 0;
+
+ context = kmalloc(sizeof *context , GFP_KERNEL);
+ if (!context) {
+ mlx4_err(mdev, "Failed to allocate qp context\n");
+ return -ENOMEM;
+ }
+
+ err = mlx4_qp_alloc(mdev->dev, qpn, qp);
+ if (err) {
+ mlx4_err(mdev, "Failed to allocate qp #%d\n", qpn);
+ goto out;
+ return err;
+ }
+ qp->event = mlx4_en_sqp_event;
+
+ memset(context, 0, sizeof *context);
+ mlx4_en_fill_qp_context(priv, 0, 0, 0, 0, qpn, cqn, srqn, context);
+
+ err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, context, qp, state);
+ if (err) {
+ mlx4_qp_remove(mdev->dev, qp);
+ mlx4_qp_free(mdev->dev, qp);
+ }
+out:
+ kfree(context);
+ return err;
+}
+
+/* Allocate rx qp's and configure them according to rss map */
+int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_rss_map *rss_map = &priv->rss_map;
+ struct mlx4_qp_context context;
+ struct mlx4_en_rss_context *rss_context;
+ void *ptr;
+ int rss_xor = mdev->profile.rss_xor;
+ u8 rss_mask = mdev->profile.rss_mask;
+ int i, srqn, qpn, cqn;
+ int err = 0;
+ int good_qps = 0;
+
+ mlx4_dbg(DRV, priv, "Configuring rss steering for port %u\n", priv->port);
+ err = mlx4_qp_reserve_range(mdev->dev, rss_map->size,
+ rss_map->size, &rss_map->base_qpn);
+ if (err) {
+ mlx4_err(mdev, "Failed reserving %d qps for port %u\n",
+ rss_map->size, priv->port);
+ return err;
+ }
+
+ for (i = 0; i < rss_map->size; i++) {
+ cqn = priv->rx_ring[rss_map->map[i]].cqn;
+ srqn = priv->rx_ring[rss_map->map[i]].srq.srqn;
+ qpn = rss_map->base_qpn + i;
+ err = mlx4_en_config_rss_qp(priv, qpn, srqn, cqn,
+ &rss_map->state[i],
+ &rss_map->qps[i]);
+ if (err)
+ goto rss_err;
+
+ ++good_qps;
+ }
+
+ /* Configure RSS indirection qp */
+ err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn);
+ if (err) {
+ mlx4_err(mdev, "Failed to reserve range for RSS "
+ "indirection qp\n");
+ goto rss_err;
+ }
+ err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp);
+ if (err) {
+ mlx4_err(mdev, "Failed to allocate RSS indirection QP\n");
+ goto reserve_err;
+ }
+ rss_map->indir_qp.event = mlx4_en_sqp_event;
+ mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn,
+ priv->rx_ring[0].cqn, 0, &context);
+
+ ptr = ((void *) &context) + 0x3c;
+ rss_context = (struct mlx4_en_rss_context *) ptr;
+ rss_context->base_qpn = cpu_to_be32(ilog2(rss_map->size) << 24 |
+ (rss_map->base_qpn));
+ rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn);
+ rss_context->hash_fn = rss_xor & 0x3;
+ rss_context->flags = rss_mask << 2;
+
+ err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context,
+ &rss_map->indir_qp, &rss_map->indir_state);
+ if (err)
+ goto indir_err;
+
+ return 0;
+
+indir_err:
+ mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state,
+ MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp);
+ mlx4_qp_remove(mdev->dev, &rss_map->indir_qp);
+ mlx4_qp_free(mdev->dev, &rss_map->indir_qp);
+reserve_err:
+ mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1);
+rss_err:
+ for (i = 0; i < good_qps; i++) {
+ mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i],
+ MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]);
+ mlx4_qp_remove(mdev->dev, &rss_map->qps[i]);
+ mlx4_qp_free(mdev->dev, &rss_map->qps[i]);
+ }
+ mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, rss_map->size);
+ return err;
+}
+
+void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_rss_map *rss_map = &priv->rss_map;
+ int i;
+
+ mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state,
+ MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp);
+ mlx4_qp_remove(mdev->dev, &rss_map->indir_qp);
+ mlx4_qp_free(mdev->dev, &rss_map->indir_qp);
+ mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1);
+
+ for (i = 0; i < rss_map->size; i++) {
+ mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i],
+ MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]);
+ mlx4_qp_remove(mdev->dev, &rss_map->qps[i]);
+ mlx4_qp_free(mdev->dev, &rss_map->qps[i]);
+ }
+ mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, rss_map->size);
+}
+
+
+
+
+
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
new file mode 100644
index 00000000000..8592f8fb847
--- /dev/null
+++ b/drivers/net/mlx4/en_tx.c
@@ -0,0 +1,820 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#include <asm/page.h>
+#include <linux/mlx4/cq.h>
+#include <linux/mlx4/qp.h>
+#include <linux/skbuff.h>
+#include <linux/if_vlan.h>
+#include <linux/vmalloc.h>
+
+#include "mlx4_en.h"
+
+enum {
+ MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */
+};
+
+static int inline_thold __read_mostly = MAX_INLINE;
+
+module_param_named(inline_thold, inline_thold, int, 0444);
+MODULE_PARM_DESC(inline_thold, "treshold for using inline data");
+
+int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring, u32 size,
+ u16 stride)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int tmp;
+ int err;
+
+ ring->size = size;
+ ring->size_mask = size - 1;
+ ring->stride = stride;
+
+ inline_thold = min(inline_thold, MAX_INLINE);
+
+ spin_lock_init(&ring->comp_lock);
+
+ tmp = size * sizeof(struct mlx4_en_tx_info);
+ ring->tx_info = vmalloc(tmp);
+ if (!ring->tx_info) {
+ mlx4_err(mdev, "Failed allocating tx_info ring\n");
+ return -ENOMEM;
+ }
+ mlx4_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n",
+ ring->tx_info, tmp);
+
+ ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL);
+ if (!ring->bounce_buf) {
+ mlx4_err(mdev, "Failed allocating bounce buffer\n");
+ err = -ENOMEM;
+ goto err_tx;
+ }
+ ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE);
+
+ err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size,
+ 2 * PAGE_SIZE);
+ if (err) {
+ mlx4_err(mdev, "Failed allocating hwq resources\n");
+ goto err_bounce;
+ }
+
+ err = mlx4_en_map_buffer(&ring->wqres.buf);
+ if (err) {
+ mlx4_err(mdev, "Failed to map TX buffer\n");
+ goto err_hwq_res;
+ }
+
+ ring->buf = ring->wqres.buf.direct.buf;
+
+ mlx4_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d "
+ "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size,
+ ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map);
+
+ err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn);
+ if (err) {
+ mlx4_err(mdev, "Failed reserving qp for tx ring.\n");
+ goto err_map;
+ }
+
+ err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp);
+ if (err) {
+ mlx4_err(mdev, "Failed allocating qp %d\n", ring->qpn);
+ goto err_reserve;
+ }
+
+ return 0;
+
+err_reserve:
+ mlx4_qp_release_range(mdev->dev, ring->qpn, 1);
+err_map:
+ mlx4_en_unmap_buffer(&ring->wqres.buf);
+err_hwq_res:
+ mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
+err_bounce:
+ kfree(ring->bounce_buf);
+ ring->bounce_buf = NULL;
+err_tx:
+ vfree(ring->tx_info);
+ ring->tx_info = NULL;
+ return err;
+}
+
+void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ mlx4_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn);
+
+ mlx4_qp_remove(mdev->dev, &ring->qp);
+ mlx4_qp_free(mdev->dev, &ring->qp);
+ mlx4_qp_release_range(mdev->dev, ring->qpn, 1);
+ mlx4_en_unmap_buffer(&ring->wqres.buf);
+ mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
+ kfree(ring->bounce_buf);
+ ring->bounce_buf = NULL;
+ vfree(ring->tx_info);
+ ring->tx_info = NULL;
+}
+
+int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring,
+ int cq, int srqn)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ ring->cqn = cq;
+ ring->prod = 0;
+ ring->cons = 0xffffffff;
+ ring->last_nr_txbb = 1;
+ ring->poll_cnt = 0;
+ ring->blocked = 0;
+ memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info));
+ memset(ring->buf, 0, ring->buf_size);
+
+ ring->qp_state = MLX4_QP_STATE_RST;
+ ring->doorbell_qpn = swab32(ring->qp.qpn << 8);
+
+ mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,
+ ring->cqn, srqn, &ring->context);
+
+ err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context,
+ &ring->qp, &ring->qp_state);
+
+ return err;
+}
+
+void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ mlx4_qp_modify(mdev->dev, NULL, ring->qp_state,
+ MLX4_QP_STATE_RST, NULL, 0, 0, &ring->qp);
+}
+
+
+static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring,
+ int index, u8 owner)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
+ struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
+ struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset;
+ struct sk_buff *skb = tx_info->skb;
+ struct skb_frag_struct *frag;
+ void *end = ring->buf + ring->buf_size;
+ int frags = skb_shinfo(skb)->nr_frags;
+ int i;
+ __be32 *ptr = (__be32 *)tx_desc;
+ __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT));
+
+ /* 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),
+ be32_to_cpu(data->byte_count),
+ PCI_DMA_TODEVICE);
+ ++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);
+ }
+ /* Stamp the freed descriptor */
+ for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) {
+ *ptr = stamp;
+ ptr += STAMP_DWORDS;
+ }
+
+ } else {
+ 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),
+ be32_to_cpu(data->byte_count),
+ PCI_DMA_TODEVICE);
+ ++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,
+ (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) {
+ *ptr = stamp;
+ ptr += STAMP_DWORDS;
+ if ((void *) ptr >= end) {
+ ptr = ring->buf;
+ stamp ^= cpu_to_be32(0x80000000);
+ }
+ }
+
+ }
+ dev_kfree_skb_any(skb);
+ return tx_info->nr_txbb;
+}
+
+
+int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int cnt = 0;
+
+ /* Skip last polled descriptor */
+ ring->cons += ring->last_nr_txbb;
+ mlx4_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n",
+ ring->cons, ring->prod);
+
+ if ((u32) (ring->prod - ring->cons) > ring->size) {
+ if (netif_msg_tx_err(priv))
+ mlx4_warn(priv->mdev, "Tx consumer passed producer!\n");
+ return 0;
+ }
+
+ while (ring->cons != ring->prod) {
+ ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring,
+ ring->cons & ring->size_mask,
+ !!(ring->cons & ring->size));
+ ring->cons += ring->last_nr_txbb;
+ cnt++;
+ }
+
+ if (cnt)
+ mlx4_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt);
+
+ return cnt;
+}
+
+void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num)
+{
+ int block = 8 / ring_num;
+ int extra = 8 - (block * ring_num);
+ int num = 0;
+ u16 ring = 1;
+ int prio;
+
+ if (ring_num == 1) {
+ for (prio = 0; prio < 8; prio++)
+ prio_map[prio] = 0;
+ return;
+ }
+
+ for (prio = 0; prio < 8; prio++) {
+ if (extra && (num == block + 1)) {
+ ring++;
+ num = 0;
+ extra--;
+ } else if (!extra && (num == block)) {
+ ring++;
+ num = 0;
+ }
+ prio_map[prio] = ring;
+ mlx4_dbg(DRV, priv, " prio:%d --> ring:%d\n", prio, ring);
+ num++;
+ }
+}
+
+static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_cq *mcq = &cq->mcq;
+ struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring];
+ struct mlx4_cqe *cqe = cq->buf;
+ u16 index;
+ u16 new_index;
+ u32 txbbs_skipped = 0;
+ u32 cq_last_sav;
+
+ /* index always points to the first TXBB of the last polled descriptor */
+ index = ring->cons & ring->size_mask;
+ new_index = be16_to_cpu(cqe->wqe_index) & ring->size_mask;
+ if (index == new_index)
+ return;
+
+ if (!priv->port_up)
+ return;
+
+ /*
+ * We use a two-stage loop:
+ * - the first samples the HW-updated CQE
+ * - the second frees TXBBs until the last sample
+ * This lets us amortize CQE cache misses, while still polling the CQ
+ * until is quiescent.
+ */
+ cq_last_sav = mcq->cons_index;
+ do {
+ do {
+ /* Skip over last polled CQE */
+ index = (index + ring->last_nr_txbb) & ring->size_mask;
+ txbbs_skipped += ring->last_nr_txbb;
+
+ /* Poll next CQE */
+ ring->last_nr_txbb = mlx4_en_free_tx_desc(
+ priv, ring, index,
+ !!((ring->cons + txbbs_skipped) &
+ ring->size));
+ ++mcq->cons_index;
+
+ } while (index != new_index);
+
+ new_index = be16_to_cpu(cqe->wqe_index) & ring->size_mask;
+ } while (index != new_index);
+ AVG_PERF_COUNTER(priv->pstats.tx_coal_avg,
+ (u32) (mcq->cons_index - cq_last_sav));
+
+ /*
+ * To prevent CQ overflow we first update CQ consumer and only then
+ * the ring consumer.
+ */
+ mlx4_cq_set_ci(mcq);
+ wmb();
+ ring->cons += txbbs_skipped;
+
+ /* Wakeup Tx queue if this ring stopped it */
+ if (unlikely(ring->blocked)) {
+ if (((u32) (ring->prod - ring->cons) <=
+ ring->size - HEADROOM - MAX_DESC_TXBBS) && !cq->armed) {
+
+ /* TODO: support multiqueue netdevs. Currently, we block
+ * when *any* ring is full. Note that:
+ * - 2 Tx rings can unblock at the same time and call
+ * netif_wake_queue(), which is OK since this
+ * operation is idempotent.
+ * - We might wake the queue just after another ring
+ * stopped it. This is no big deal because the next
+ * transmission on that ring would stop the queue.
+ */
+ ring->blocked = 0;
+ netif_wake_queue(dev);
+ priv->port_stats.wake_queue++;
+ }
+ }
+}
+
+void mlx4_en_tx_irq(struct mlx4_cq *mcq)
+{
+ struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq);
+ struct mlx4_en_priv *priv = netdev_priv(cq->dev);
+ struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring];
+
+ spin_lock_irq(&ring->comp_lock);
+ cq->armed = 0;
+ mlx4_en_process_tx_cq(cq->dev, cq);
+ if (ring->blocked)
+ mlx4_en_arm_cq(priv, cq);
+ else
+ mod_timer(&cq->timer, jiffies + 1);
+ spin_unlock_irq(&ring->comp_lock);
+}
+
+
+void mlx4_en_poll_tx_cq(unsigned long data)
+{
+ struct mlx4_en_cq *cq = (struct mlx4_en_cq *) data;
+ struct mlx4_en_priv *priv = netdev_priv(cq->dev);
+ struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring];
+ u32 inflight;
+
+ INC_PERF_COUNTER(priv->pstats.tx_poll);
+
+ netif_tx_lock(priv->dev);
+ spin_lock_irq(&ring->comp_lock);
+ mlx4_en_process_tx_cq(cq->dev, cq);
+ inflight = (u32) (ring->prod - ring->cons - ring->last_nr_txbb);
+
+ /* If there are still packets in flight and the timer has not already
+ * been scheduled by the Tx routine then schedule it here to guarantee
+ * completion processing of these packets */
+ if (inflight && priv->port_up)
+ mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT);
+
+ spin_unlock_irq(&ring->comp_lock);
+ netif_tx_unlock(priv->dev);
+}
+
+static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring,
+ u32 index,
+ unsigned int desc_size)
+{
+ u32 copy = (ring->size - index) * TXBB_SIZE;
+ int i;
+
+ for (i = desc_size - copy - 4; i >= 0; i -= 4) {
+ if ((i & (TXBB_SIZE - 1)) == 0)
+ wmb();
+
+ *((u32 *) (ring->buf + i)) =
+ *((u32 *) (ring->bounce_buf + copy + i));
+ }
+
+ for (i = copy - 4; i >= 4 ; i -= 4) {
+ if ((i & (TXBB_SIZE - 1)) == 0)
+ wmb();
+
+ *((u32 *) (ring->buf + index * TXBB_SIZE + i)) =
+ *((u32 *) (ring->bounce_buf + i));
+ }
+
+ /* Return real descriptor location */
+ return ring->buf + index * TXBB_SIZE;
+}
+
+static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind)
+{
+ struct mlx4_en_cq *cq = &priv->tx_cq[tx_ind];
+ struct mlx4_en_tx_ring *ring = &priv->tx_ring[tx_ind];
+
+ /* If we don't have a pending timer, set one up to catch our recent
+ post in case the interface becomes idle */
+ if (!timer_pending(&cq->timer))
+ mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT);
+
+ /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */
+ if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0)
+ mlx4_en_process_tx_cq(priv->dev, cq);
+}
+
+static void *get_frag_ptr(struct sk_buff *skb)
+{
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
+ struct page *page = frag->page;
+ void *ptr;
+
+ ptr = page_address(page);
+ if (unlikely(!ptr))
+ return NULL;
+
+ return ptr + frag->page_offset;
+}
+
+static int is_inline(struct sk_buff *skb, void **pfrag)
+{
+ void *ptr;
+
+ if (inline_thold && !skb_is_gso(skb) && skb->len <= inline_thold) {
+ if (skb_shinfo(skb)->nr_frags == 1) {
+ ptr = get_frag_ptr(skb);
+ if (unlikely(!ptr))
+ return 0;
+
+ if (pfrag)
+ *pfrag = ptr;
+
+ return 1;
+ } else if (unlikely(skb_shinfo(skb)->nr_frags))
+ return 0;
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+static int inline_size(struct sk_buff *skb)
+{
+ if (skb->len + CTRL_SIZE + sizeof(struct mlx4_wqe_inline_seg)
+ <= MLX4_INLINE_ALIGN)
+ return ALIGN(skb->len + CTRL_SIZE +
+ sizeof(struct mlx4_wqe_inline_seg), 16);
+ else
+ return ALIGN(skb->len + CTRL_SIZE + 2 *
+ sizeof(struct mlx4_wqe_inline_seg), 16);
+}
+
+static int get_real_size(struct sk_buff *skb, struct net_device *dev,
+ int *lso_header_size)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int real_size;
+
+ if (skb_is_gso(skb)) {
+ *lso_header_size = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ real_size = CTRL_SIZE + skb_shinfo(skb)->nr_frags * DS_SIZE +
+ ALIGN(*lso_header_size + 4, DS_SIZE);
+ if (unlikely(*lso_header_size != skb_headlen(skb))) {
+ /* We add a segment for the skb linear buffer only if
+ * it contains data */
+ if (*lso_header_size < skb_headlen(skb))
+ real_size += DS_SIZE;
+ else {
+ if (netif_msg_tx_err(priv))
+ mlx4_warn(mdev, "Non-linear headers\n");
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+ }
+ if (unlikely(*lso_header_size > MAX_LSO_HDR_SIZE)) {
+ if (netif_msg_tx_err(priv))
+ mlx4_warn(mdev, "LSO header size too big\n");
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+ } else {
+ *lso_header_size = 0;
+ if (!is_inline(skb, NULL))
+ real_size = CTRL_SIZE + (skb_shinfo(skb)->nr_frags + 1) * DS_SIZE;
+ else
+ real_size = inline_size(skb);
+ }
+
+ return real_size;
+}
+
+static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *skb,
+ int real_size, u16 *vlan_tag, int tx_ind, void *fragptr)
+{
+ struct mlx4_wqe_inline_seg *inl = &tx_desc->inl;
+ int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - sizeof *inl;
+
+ if (skb->len <= spc) {
+ inl->byte_count = cpu_to_be32(1 << 31 | skb->len);
+ skb_copy_from_linear_data(skb, inl + 1, skb_headlen(skb));
+ if (skb_shinfo(skb)->nr_frags)
+ memcpy(((void *)(inl + 1)) + skb_headlen(skb), fragptr,
+ skb_shinfo(skb)->frags[0].size);
+
+ } else {
+ inl->byte_count = cpu_to_be32(1 << 31 | spc);
+ if (skb_headlen(skb) <= spc) {
+ skb_copy_from_linear_data(skb, inl + 1, skb_headlen(skb));
+ if (skb_headlen(skb) < spc) {
+ memcpy(((void *)(inl + 1)) + skb_headlen(skb),
+ fragptr, spc - skb_headlen(skb));
+ fragptr += spc - skb_headlen(skb);
+ }
+ inl = (void *) (inl + 1) + spc;
+ memcpy(((void *)(inl + 1)), fragptr, skb->len - spc);
+ } else {
+ skb_copy_from_linear_data(skb, inl + 1, spc);
+ inl = (void *) (inl + 1) + spc;
+ skb_copy_from_linear_data_offset(skb, spc, inl + 1,
+ skb_headlen(skb) - spc);
+ if (skb_shinfo(skb)->nr_frags)
+ memcpy(((void *)(inl + 1)) + skb_headlen(skb) - spc,
+ fragptr, skb_shinfo(skb)->frags[0].size);
+ }
+
+ wmb();
+ inl->byte_count = cpu_to_be32(1 << 31 | (skb->len - spc));
+ }
+ tx_desc->ctrl.vlan_tag = cpu_to_be16(*vlan_tag);
+ tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN * !!(*vlan_tag);
+ tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f;
+}
+
+static int get_vlan_info(struct mlx4_en_priv *priv, struct sk_buff *skb,
+ u16 *vlan_tag)
+{
+ int tx_ind;
+
+ /* Obtain VLAN information if present */
+ if (priv->vlgrp && vlan_tx_tag_present(skb)) {
+ *vlan_tag = vlan_tx_tag_get(skb);
+ /* Set the Tx ring to use according to vlan priority */
+ tx_ind = priv->tx_prio_map[*vlan_tag >> 13];
+ } else {
+ *vlan_tag = 0;
+ tx_ind = 0;
+ }
+ return tx_ind;
+}
+
+int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_tx_ring *ring;
+ struct mlx4_en_cq *cq;
+ struct mlx4_en_tx_desc *tx_desc;
+ struct mlx4_wqe_data_seg *data;
+ struct skb_frag_struct *frag;
+ struct mlx4_en_tx_info *tx_info;
+ int tx_ind = 0;
+ int nr_txbb;
+ int desc_size;
+ int real_size;
+ dma_addr_t dma;
+ u32 index;
+ __be32 op_own;
+ u16 vlan_tag;
+ int i;
+ int lso_header_size;
+ void *fragptr;
+
+ if (unlikely(!skb->len)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ real_size = get_real_size(skb, dev, &lso_header_size);
+ if (unlikely(!real_size))
+ return NETDEV_TX_OK;
+
+ /* Allign descriptor to TXBB size */
+ desc_size = ALIGN(real_size, TXBB_SIZE);
+ nr_txbb = desc_size / TXBB_SIZE;
+ if (unlikely(nr_txbb > MAX_DESC_TXBBS)) {
+ if (netif_msg_tx_err(priv))
+ mlx4_warn(mdev, "Oversized header or SG list\n");
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ tx_ind = get_vlan_info(priv, skb, &vlan_tag);
+ ring = &priv->tx_ring[tx_ind];
+
+ /* Check available TXBBs And 2K spare for prefetch */
+ if (unlikely(((int)(ring->prod - ring->cons)) >
+ ring->size - HEADROOM - MAX_DESC_TXBBS)) {
+ /* every full Tx ring stops queue.
+ * TODO: implement multi-queue support (per-queue stop) */
+ netif_stop_queue(dev);
+ ring->blocked = 1;
+ priv->port_stats.queue_stopped++;
+
+ /* Use interrupts to find out when queue opened */
+ cq = &priv->tx_cq[tx_ind];
+ mlx4_en_arm_cq(priv, cq);
+ return NETDEV_TX_BUSY;
+ }
+
+ /* Now that we know what Tx ring to use */
+ if (unlikely(!priv->port_up)) {
+ if (netif_msg_tx_err(priv))
+ mlx4_warn(mdev, "xmit: port down!\n");
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ /* Track current inflight packets for performance analysis */
+ AVG_PERF_COUNTER(priv->pstats.inflight_avg,
+ (u32) (ring->prod - ring->cons - 1));
+
+ /* Packet is good - grab an index and transmit it */
+ index = ring->prod & ring->size_mask;
+
+ /* See if we have enough space for whole descriptor TXBB for setting
+ * SW ownership on next descriptor; if not, use a bounce buffer. */
+ if (likely(index + nr_txbb <= ring->size))
+ tx_desc = ring->buf + index * TXBB_SIZE;
+ else
+ tx_desc = (struct mlx4_en_tx_desc *) ring->bounce_buf;
+
+ /* Save skb in tx_info ring */
+ tx_info = &ring->tx_info[index];
+ tx_info->skb = skb;
+ tx_info->nr_txbb = nr_txbb;
+
+ /* Prepare ctrl segement apart opcode+ownership, which depends on
+ * whether LSO is used */
+ tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag);
+ tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN * !!vlan_tag;
+ tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f;
+ tx_desc->ctrl.srcrb_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE |
+ MLX4_WQE_CTRL_SOLICITED);
+ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+ tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM |
+ MLX4_WQE_CTRL_TCP_UDP_CSUM);
+ priv->port_stats.tx_chksum_offload++;
+ }
+
+ /* Handle LSO (TSO) packets */
+ if (lso_header_size) {
+ /* Mark opcode as LSO */
+ op_own = cpu_to_be32(MLX4_OPCODE_LSO | (1 << 6)) |
+ ((ring->prod & ring->size) ?
+ cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0);
+
+ /* Fill in the LSO prefix */
+ tx_desc->lso.mss_hdr_size = cpu_to_be32(
+ skb_shinfo(skb)->gso_size << 16 | lso_header_size);
+
+ /* Copy headers;
+ * note that we already verified that it is linear */
+ memcpy(tx_desc->lso.header, skb->data, lso_header_size);
+ data = ((void *) &tx_desc->lso +
+ ALIGN(lso_header_size + 4, DS_SIZE));
+
+ priv->port_stats.tso_packets++;
+ i = ((skb->len - lso_header_size) / skb_shinfo(skb)->gso_size) +
+ !!((skb->len - lso_header_size) % skb_shinfo(skb)->gso_size);
+ ring->bytes += skb->len + (i - 1) * lso_header_size;
+ ring->packets += i;
+ } else {
+ /* Normal (Non LSO) packet */
+ op_own = cpu_to_be32(MLX4_OPCODE_SEND) |
+ ((ring->prod & ring->size) ?
+ cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0);
+ data = &tx_desc->data;
+ ring->bytes += max(skb->len, (unsigned int) ETH_ZLEN);
+ ring->packets++;
+
+ }
+ AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, skb->len);
+
+
+ /* valid only for none inline segments */
+ tx_info->data_offset = (void *) data - (void *) tx_desc;
+
+ tx_info->linear = (lso_header_size < skb_headlen(skb) && !is_inline(skb, NULL)) ? 1 : 0;
+ data += skb_shinfo(skb)->nr_frags + tx_info->linear - 1;
+
+ if (!is_inline(skb, &fragptr)) {
+ /* Map fragments */
+ for (i = skb_shinfo(skb)->nr_frags - 1; i >= 0; i--) {
+ frag = &skb_shinfo(skb)->frags[i];
+ dma = pci_map_page(mdev->dev->pdev, frag->page, frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
+ data->addr = cpu_to_be64(dma);
+ data->lkey = cpu_to_be32(mdev->mr.key);
+ wmb();
+ data->byte_count = cpu_to_be32(frag->size);
+ --data;
+ }
+
+ /* Map linear part */
+ if (tx_info->linear) {
+ dma = pci_map_single(mdev->dev->pdev, skb->data + lso_header_size,
+ skb_headlen(skb) - lso_header_size, PCI_DMA_TODEVICE);
+ data->addr = cpu_to_be64(dma);
+ data->lkey = cpu_to_be32(mdev->mr.key);
+ wmb();
+ data->byte_count = cpu_to_be32(skb_headlen(skb) - lso_header_size);
+ }
+ } else
+ build_inline_wqe(tx_desc, skb, real_size, &vlan_tag, tx_ind, fragptr);
+
+ ring->prod += nr_txbb;
+
+ /* If we used a bounce buffer then copy descriptor back into place */
+ if (tx_desc == (struct mlx4_en_tx_desc *) ring->bounce_buf)
+ tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size);
+
+ /* Run destructor before passing skb to HW */
+ if (likely(!skb_shared(skb)))
+ skb_orphan(skb);
+
+ /* Ensure new descirptor hits memory
+ * before setting ownership of this descriptor to HW */
+ wmb();
+ tx_desc->ctrl.owner_opcode = op_own;
+
+ /* Ring doorbell! */
+ wmb();
+ writel(ring->doorbell_qpn, mdev->uar_map + MLX4_SEND_DOORBELL);
+ dev->trans_start = jiffies;
+
+ /* Poll CQ here */
+ mlx4_en_xmit_poll(priv, tx_ind);
+
+ return 0;
+}
+
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 8a8b56135a5..de169338cd9 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -558,7 +558,7 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
int i;
err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs,
- dev->caps.num_eqs - 1, dev->caps.reserved_eqs);
+ dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0);
if (err)
return err;
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index 7e32955da98..be09fdb79cb 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -88,6 +88,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags)
[ 8] = "P_Key violation counter",
[ 9] = "Q_Key violation counter",
[10] = "VMM",
+ [12] = "DPDP",
[16] = "MW support",
[17] = "APM support",
[18] = "Atomic ops support",
@@ -346,7 +347,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
dev_cap->max_vl[i] = field >> 4;
MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
- dev_cap->max_mtu[i] = field >> 4;
+ dev_cap->ib_mtu[i] = field >> 4;
dev_cap->max_port_width[i] = field & 0xf;
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET);
dev_cap->max_gids[i] = 1 << (field & 0xf);
@@ -354,9 +355,13 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->max_pkeys[i] = 1 << (field & 0xf);
}
} else {
+#define QUERY_PORT_SUPPORTED_TYPE_OFFSET 0x00
#define QUERY_PORT_MTU_OFFSET 0x01
+#define QUERY_PORT_ETH_MTU_OFFSET 0x02
#define QUERY_PORT_WIDTH_OFFSET 0x06
#define QUERY_PORT_MAX_GID_PKEY_OFFSET 0x07
+#define QUERY_PORT_MAC_OFFSET 0x08
+#define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a
#define QUERY_PORT_MAX_VL_OFFSET 0x0b
for (i = 1; i <= dev_cap->num_ports; ++i) {
@@ -365,8 +370,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
if (err)
goto out;
+ MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
+ dev_cap->supported_port_types[i] = field & 3;
MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET);
- dev_cap->max_mtu[i] = field & 0xf;
+ dev_cap->ib_mtu[i] = field & 0xf;
MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET);
dev_cap->max_port_width[i] = field & 0xf;
MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET);
@@ -374,6 +381,11 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->max_pkeys[i] = 1 << (field & 0xf);
MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET);
dev_cap->max_vl[i] = field & 0xf;
+ MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET);
+ dev_cap->log_max_macs[i] = field & 0xf;
+ dev_cap->log_max_vlans[i] = field >> 4;
+ MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET);
+ MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET);
}
}
@@ -407,7 +419,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n",
dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz);
mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n",
- dev_cap->local_ca_ack_delay, 128 << dev_cap->max_mtu[1],
+ dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1],
dev_cap->max_port_width[1]);
mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n",
dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg);
@@ -819,7 +831,7 @@ int mlx4_INIT_PORT(struct mlx4_dev *dev, int port)
flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT;
MLX4_PUT(inbox, flags, INIT_PORT_FLAGS_OFFSET);
- field = 128 << dev->caps.mtu_cap[port];
+ field = 128 << dev->caps.ib_mtu_cap[port];
MLX4_PUT(inbox, field, INIT_PORT_MTU_OFFSET);
field = dev->caps.gid_table_len[port];
MLX4_PUT(inbox, field, INIT_PORT_MAX_GID_OFFSET);
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h
index decbb5c2ad4..526d7f30c04 100644
--- a/drivers/net/mlx4/fw.h
+++ b/drivers/net/mlx4/fw.h
@@ -66,11 +66,13 @@ struct mlx4_dev_cap {
int local_ca_ack_delay;
int num_ports;
u32 max_msg_sz;
- int max_mtu[MLX4_MAX_PORTS + 1];
+ int ib_mtu[MLX4_MAX_PORTS + 1];
int max_port_width[MLX4_MAX_PORTS + 1];
int max_vl[MLX4_MAX_PORTS + 1];
int max_gids[MLX4_MAX_PORTS + 1];
int max_pkeys[MLX4_MAX_PORTS + 1];
+ u64 def_mac[MLX4_MAX_PORTS + 1];
+ u16 eth_mtu[MLX4_MAX_PORTS + 1];
u16 stat_rate_support;
u32 flags;
int reserved_uars;
@@ -102,6 +104,9 @@ struct mlx4_dev_cap {
u32 reserved_lkey;
u64 max_icm_sz;
int max_gso_sz;
+ u8 supported_port_types[MLX4_MAX_PORTS + 1];
+ u8 log_max_macs[MLX4_MAX_PORTS + 1];
+ u8 log_max_vlans[MLX4_MAX_PORTS + 1];
};
struct mlx4_adapter {
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 1252a919de2..468921b8f4b 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -85,6 +85,57 @@ static struct mlx4_profile default_profile = {
.num_mtt = 1 << 20,
};
+static int log_num_mac = 2;
+module_param_named(log_num_mac, log_num_mac, int, 0444);
+MODULE_PARM_DESC(log_num_mac, "Log2 max number of MACs per ETH port (1-7)");
+
+static int log_num_vlan;
+module_param_named(log_num_vlan, log_num_vlan, int, 0444);
+MODULE_PARM_DESC(log_num_vlan, "Log2 max number of VLANs per ETH port (0-7)");
+
+static int use_prio;
+module_param_named(use_prio, use_prio, bool, 0444);
+MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports "
+ "(0/1, default 0)");
+
+static int mlx4_check_port_params(struct mlx4_dev *dev,
+ enum mlx4_port_type *port_type)
+{
+ int i;
+
+ for (i = 0; i < dev->caps.num_ports - 1; i++) {
+ if (port_type[i] != port_type[i+1] &&
+ !(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) {
+ mlx4_err(dev, "Only same port types supported "
+ "on this HCA, aborting.\n");
+ return -EINVAL;
+ }
+ }
+ if ((port_type[0] == MLX4_PORT_TYPE_ETH) &&
+ (port_type[1] == MLX4_PORT_TYPE_IB)) {
+ mlx4_err(dev, "eth-ib configuration is not supported.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dev->caps.num_ports; i++) {
+ if (!(port_type[i] & dev->caps.supported_type[i+1])) {
+ mlx4_err(dev, "Requested port type for port %d is not "
+ "supported on this HCA\n", i + 1);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static void mlx4_set_port_mask(struct mlx4_dev *dev)
+{
+ int i;
+
+ dev->caps.port_mask = 0;
+ for (i = 1; i <= dev->caps.num_ports; ++i)
+ if (dev->caps.port_type[i] == MLX4_PORT_TYPE_IB)
+ dev->caps.port_mask |= 1 << (i - 1);
+}
static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
{
int err;
@@ -120,10 +171,13 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.num_ports = dev_cap->num_ports;
for (i = 1; i <= dev->caps.num_ports; ++i) {
dev->caps.vl_cap[i] = dev_cap->max_vl[i];
- dev->caps.mtu_cap[i] = dev_cap->max_mtu[i];
+ dev->caps.ib_mtu_cap[i] = dev_cap->ib_mtu[i];
dev->caps.gid_table_len[i] = dev_cap->max_gids[i];
dev->caps.pkey_table_len[i] = dev_cap->max_pkeys[i];
dev->caps.port_width_cap[i] = dev_cap->max_port_width[i];
+ dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i];
+ dev->caps.def_mac[i] = dev_cap->def_mac[i];
+ dev->caps.supported_type[i] = dev_cap->supported_port_types[i];
}
dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE;
@@ -134,7 +188,6 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.max_rq_sg = dev_cap->max_rq_sg;
dev->caps.max_wqes = dev_cap->max_qp_sz;
dev->caps.max_qp_init_rdma = dev_cap->max_requester_per_qp;
- dev->caps.reserved_qps = dev_cap->reserved_qps;
dev->caps.max_srq_wqes = dev_cap->max_srq_sz;
dev->caps.max_srq_sge = dev_cap->max_rq_sg - 1;
dev->caps.reserved_srqs = dev_cap->reserved_srqs;
@@ -163,9 +216,138 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.stat_rate_support = dev_cap->stat_rate_support;
dev->caps.max_gso_sz = dev_cap->max_gso_sz;
+ dev->caps.log_num_macs = log_num_mac;
+ dev->caps.log_num_vlans = log_num_vlan;
+ dev->caps.log_num_prios = use_prio ? 3 : 0;
+
+ for (i = 1; i <= dev->caps.num_ports; ++i) {
+ if (dev->caps.supported_type[i] != MLX4_PORT_TYPE_ETH)
+ dev->caps.port_type[i] = MLX4_PORT_TYPE_IB;
+ else
+ dev->caps.port_type[i] = MLX4_PORT_TYPE_ETH;
+
+ if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) {
+ dev->caps.log_num_macs = dev_cap->log_max_macs[i];
+ mlx4_warn(dev, "Requested number of MACs is too much "
+ "for port %d, reducing to %d.\n",
+ i, 1 << dev->caps.log_num_macs);
+ }
+ if (dev->caps.log_num_vlans > dev_cap->log_max_vlans[i]) {
+ dev->caps.log_num_vlans = dev_cap->log_max_vlans[i];
+ mlx4_warn(dev, "Requested number of VLANs is too much "
+ "for port %d, reducing to %d.\n",
+ i, 1 << dev->caps.log_num_vlans);
+ }
+ }
+
+ mlx4_set_port_mask(dev);
+
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps;
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] =
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] =
+ (1 << dev->caps.log_num_macs) *
+ (1 << dev->caps.log_num_vlans) *
+ (1 << dev->caps.log_num_prios) *
+ dev->caps.num_ports;
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH] = MLX4_NUM_FEXCH;
+
+ dev->caps.reserved_qps = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] +
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] +
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] +
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH];
+
return 0;
}
+/*
+ * Change the port configuration of the device.
+ * Every user of this function must hold the port mutex.
+ */
+static int mlx4_change_port_types(struct mlx4_dev *dev,
+ enum mlx4_port_type *port_types)
+{
+ int err = 0;
+ int change = 0;
+ int port;
+
+ for (port = 0; port < dev->caps.num_ports; port++) {
+ if (port_types[port] != dev->caps.port_type[port + 1]) {
+ change = 1;
+ dev->caps.port_type[port + 1] = port_types[port];
+ }
+ }
+ if (change) {
+ mlx4_unregister_device(dev);
+ for (port = 1; port <= dev->caps.num_ports; port++) {
+ mlx4_CLOSE_PORT(dev, port);
+ err = mlx4_SET_PORT(dev, port);
+ if (err) {
+ mlx4_err(dev, "Failed to set port %d, "
+ "aborting\n", port);
+ goto out;
+ }
+ }
+ mlx4_set_port_mask(dev);
+ err = mlx4_register_device(dev);
+ }
+
+out:
+ return err;
+}
+
+static ssize_t show_port_type(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
+ port_attr);
+ struct mlx4_dev *mdev = info->dev;
+
+ return sprintf(buf, "%s\n",
+ mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_IB ?
+ "ib" : "eth");
+}
+
+static ssize_t set_port_type(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
+ port_attr);
+ struct mlx4_dev *mdev = info->dev;
+ struct mlx4_priv *priv = mlx4_priv(mdev);
+ enum mlx4_port_type types[MLX4_MAX_PORTS];
+ int i;
+ int err = 0;
+
+ if (!strcmp(buf, "ib\n"))
+ info->tmp_type = MLX4_PORT_TYPE_IB;
+ else if (!strcmp(buf, "eth\n"))
+ info->tmp_type = MLX4_PORT_TYPE_ETH;
+ else {
+ mlx4_err(mdev, "%s is not supported port type\n", buf);
+ return -EINVAL;
+ }
+
+ mutex_lock(&priv->port_mutex);
+ for (i = 0; i < mdev->caps.num_ports; i++)
+ types[i] = priv->port[i+1].tmp_type ? priv->port[i+1].tmp_type :
+ mdev->caps.port_type[i+1];
+
+ err = mlx4_check_port_params(mdev, types);
+ if (err)
+ goto out;
+
+ for (i = 1; i <= mdev->caps.num_ports; i++)
+ priv->port[i].tmp_type = 0;
+
+ err = mlx4_change_port_types(mdev, types);
+
+out:
+ mutex_unlock(&priv->port_mutex);
+ return err ? err : count;
+}
+
static int mlx4_load_fw(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -211,7 +393,8 @@ static int mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
((u64) (MLX4_CMPT_TYPE_QP *
cmpt_entry_sz) << MLX4_CMPT_SHIFT),
cmpt_entry_sz, dev->caps.num_qps,
- dev->caps.reserved_qps, 0, 0);
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
+ 0, 0);
if (err)
goto err;
@@ -336,7 +519,8 @@ static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
init_hca->qpc_base,
dev_cap->qpc_entry_sz,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0, 0);
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
+ 0, 0);
if (err) {
mlx4_err(dev, "Failed to map QP context memory, aborting.\n");
goto err_unmap_dmpt;
@@ -346,7 +530,8 @@ static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
init_hca->auxc_base,
dev_cap->aux_entry_sz,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0, 0);
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
+ 0, 0);
if (err) {
mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n");
goto err_unmap_qp;
@@ -356,7 +541,8 @@ static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
init_hca->altc_base,
dev_cap->altc_entry_sz,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0, 0);
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
+ 0, 0);
if (err) {
mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n");
goto err_unmap_auxc;
@@ -366,7 +552,8 @@ static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
init_hca->rdmarc_base,
dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0, 0);
+ dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
+ 0, 0);
if (err) {
mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n");
goto err_unmap_altc;
@@ -565,6 +752,7 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
+ int port;
err = mlx4_init_uar_table(dev);
if (err) {
@@ -663,8 +851,20 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
goto err_qp_table_free;
}
+ for (port = 1; port <= dev->caps.num_ports; port++) {
+ err = mlx4_SET_PORT(dev, port);
+ if (err) {
+ mlx4_err(dev, "Failed to set port %d, aborting\n",
+ port);
+ goto err_mcg_table_free;
+ }
+ }
+
return 0;
+err_mcg_table_free:
+ mlx4_cleanup_mcg_table(dev);
+
err_qp_table_free:
mlx4_cleanup_qp_table(dev);
@@ -728,11 +928,45 @@ no_msi:
priv->eq_table.eq[i].irq = dev->pdev->irq;
}
+static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
+{
+ struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
+ int err = 0;
+
+ info->dev = dev;
+ info->port = port;
+ mlx4_init_mac_table(dev, &info->mac_table);
+ mlx4_init_vlan_table(dev, &info->vlan_table);
+
+ sprintf(info->dev_name, "mlx4_port%d", port);
+ info->port_attr.attr.name = info->dev_name;
+ info->port_attr.attr.mode = S_IRUGO | S_IWUSR;
+ info->port_attr.show = show_port_type;
+ info->port_attr.store = set_port_type;
+
+ err = device_create_file(&dev->pdev->dev, &info->port_attr);
+ if (err) {
+ mlx4_err(dev, "Failed to create file for port %d\n", port);
+ info->port = -1;
+ }
+
+ return err;
+}
+
+static void mlx4_cleanup_port_info(struct mlx4_port_info *info)
+{
+ if (info->port < 0)
+ return;
+
+ device_remove_file(&info->dev->pdev->dev, &info->port_attr);
+}
+
static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct mlx4_priv *priv;
struct mlx4_dev *dev;
int err;
+ int port;
printk(KERN_INFO PFX "Initializing %s\n",
pci_name(pdev));
@@ -807,6 +1041,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&priv->ctx_list);
spin_lock_init(&priv->ctx_lock);
+ mutex_init(&priv->port_mutex);
+
INIT_LIST_HEAD(&priv->pgdir_list);
mutex_init(&priv->pgdir_mutex);
@@ -842,15 +1078,24 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto err_close;
+ for (port = 1; port <= dev->caps.num_ports; port++) {
+ err = mlx4_init_port_info(dev, port);
+ if (err)
+ goto err_port;
+ }
+
err = mlx4_register_device(dev);
if (err)
- goto err_cleanup;
+ goto err_port;
pci_set_drvdata(pdev, dev);
return 0;
-err_cleanup:
+err_port:
+ for (port = 1; port <= dev->caps.num_ports; port++)
+ mlx4_cleanup_port_info(&priv->port[port]);
+
mlx4_cleanup_mcg_table(dev);
mlx4_cleanup_qp_table(dev);
mlx4_cleanup_srq_table(dev);
@@ -907,8 +1152,10 @@ static void mlx4_remove_one(struct pci_dev *pdev)
if (dev) {
mlx4_unregister_device(dev);
- for (p = 1; p <= dev->caps.num_ports; ++p)
+ for (p = 1; p <= dev->caps.num_ports; p++) {
+ mlx4_cleanup_port_info(&priv->port[p]);
mlx4_CLOSE_PORT(dev, p);
+ }
mlx4_cleanup_mcg_table(dev);
mlx4_cleanup_qp_table(dev);
@@ -948,6 +1195,8 @@ static struct pci_device_id mlx4_pci_table[] = {
{ PCI_VDEVICE(MELLANOX, 0x6354) }, /* MT25408 "Hermon" QDR */
{ PCI_VDEVICE(MELLANOX, 0x6732) }, /* MT25408 "Hermon" DDR PCIe gen2 */
{ PCI_VDEVICE(MELLANOX, 0x673c) }, /* MT25408 "Hermon" QDR PCIe gen2 */
+ { PCI_VDEVICE(MELLANOX, 0x6368) }, /* MT25408 "Hermon" EN 10GigE */
+ { PCI_VDEVICE(MELLANOX, 0x6750) }, /* MT25408 "Hermon" EN 10GigE PCIe gen2 */
{ 0, }
};
@@ -960,10 +1209,28 @@ static struct pci_driver mlx4_driver = {
.remove = __devexit_p(mlx4_remove_one)
};
+static int __init mlx4_verify_params(void)
+{
+ if ((log_num_mac < 0) || (log_num_mac > 7)) {
+ printk(KERN_WARNING "mlx4_core: bad num_mac: %d\n", log_num_mac);
+ return -1;
+ }
+
+ if ((log_num_vlan < 0) || (log_num_vlan > 7)) {
+ printk(KERN_WARNING "mlx4_core: bad num_vlan: %d\n", log_num_vlan);
+ return -1;
+ }
+
+ return 0;
+}
+
static int __init mlx4_init(void)
{
int ret;
+ if (mlx4_verify_params())
+ return -EINVAL;
+
ret = mlx4_catas_init();
if (ret)
return ret;
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index c83f88ce073..592c01ae2c5 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -368,8 +368,8 @@ int mlx4_init_mcg_table(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
- err = mlx4_bitmap_init(&priv->mcg_table.bitmap,
- dev->caps.num_amgms, dev->caps.num_amgms - 1, 0);
+ err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
+ dev->caps.num_amgms - 1, 0, 0);
if (err)
return err;
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 5337e3ac3e7..fa431fad0ee 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -111,6 +111,7 @@ struct mlx4_bitmap {
u32 last;
u32 top;
u32 max;
+ u32 reserved_top;
u32 mask;
spinlock_t lock;
unsigned long *table;
@@ -251,6 +252,38 @@ struct mlx4_catas_err {
struct list_head list;
};
+#define MLX4_MAX_MAC_NUM 128
+#define MLX4_MAC_TABLE_SIZE (MLX4_MAX_MAC_NUM << 3)
+
+struct mlx4_mac_table {
+ __be64 entries[MLX4_MAX_MAC_NUM];
+ int refs[MLX4_MAX_MAC_NUM];
+ struct mutex mutex;
+ int total;
+ int max;
+};
+
+#define MLX4_MAX_VLAN_NUM 128
+#define MLX4_VLAN_TABLE_SIZE (MLX4_MAX_VLAN_NUM << 2)
+
+struct mlx4_vlan_table {
+ __be32 entries[MLX4_MAX_VLAN_NUM];
+ int refs[MLX4_MAX_VLAN_NUM];
+ struct mutex mutex;
+ int total;
+ int max;
+};
+
+struct mlx4_port_info {
+ struct mlx4_dev *dev;
+ int port;
+ char dev_name[16];
+ struct device_attribute port_attr;
+ enum mlx4_port_type tmp_type;
+ struct mlx4_mac_table mac_table;
+ struct mlx4_vlan_table vlan_table;
+};
+
struct mlx4_priv {
struct mlx4_dev dev;
@@ -279,6 +312,8 @@ struct mlx4_priv {
struct mlx4_uar driver_uar;
void __iomem *kar;
+ struct mlx4_port_info port[MLX4_MAX_PORTS + 1];
+ struct mutex port_mutex;
};
static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
@@ -288,7 +323,10 @@ static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap);
void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj);
-int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved);
+u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align);
+void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt);
+int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
+ u32 reserved_bot, u32 resetrved_top);
void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap);
int mlx4_reset(struct mlx4_dev *dev);
@@ -346,4 +384,9 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type);
void mlx4_handle_catas_err(struct mlx4_dev *dev);
+void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table);
+void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table);
+
+int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port);
+
#endif /* MLX4_H */
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
new file mode 100644
index 00000000000..11fb17c6e97
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MLX4_EN_H_
+#define _MLX4_EN_H_
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/inet_lro.h>
+
+#include <linux/mlx4/device.h>
+#include <linux/mlx4/qp.h>
+#include <linux/mlx4/cq.h>
+#include <linux/mlx4/srq.h>
+#include <linux/mlx4/doorbell.h>
+
+#include "en_port.h"
+
+#define DRV_NAME "mlx4_en"
+#define DRV_VERSION "1.4.0"
+#define DRV_RELDATE "Sep 2008"
+
+
+#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
+
+#define mlx4_dbg(mlevel, priv, format, arg...) \
+ if (NETIF_MSG_##mlevel & priv->msg_enable) \
+ printk(KERN_DEBUG "%s %s: " format , DRV_NAME ,\
+ (&priv->mdev->pdev->dev)->bus_id , ## arg)
+
+#define mlx4_err(mdev, format, arg...) \
+ printk(KERN_ERR "%s %s: " format , DRV_NAME ,\
+ (&mdev->pdev->dev)->bus_id , ## arg)
+#define mlx4_info(mdev, format, arg...) \
+ printk(KERN_INFO "%s %s: " format , DRV_NAME ,\
+ (&mdev->pdev->dev)->bus_id , ## arg)
+#define mlx4_warn(mdev, format, arg...) \
+ printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\
+ (&mdev->pdev->dev)->bus_id , ## arg)
+
+/*
+ * Device constants
+ */
+
+
+#define MLX4_EN_PAGE_SHIFT 12
+#define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT)
+#define MAX_TX_RINGS 16
+#define MAX_RX_RINGS 16
+#define MAX_RSS_MAP_SIZE 64
+#define RSS_FACTOR 2
+#define TXBB_SIZE 64
+#define HEADROOM (2048 / TXBB_SIZE + 1)
+#define MAX_LSO_HDR_SIZE 92
+#define STAMP_STRIDE 64
+#define STAMP_DWORDS (STAMP_STRIDE / 4)
+#define STAMP_SHIFT 31
+#define STAMP_VAL 0x7fffffff
+#define STATS_DELAY (HZ / 4)
+
+/* Typical TSO descriptor with 16 gather entries is 352 bytes... */
+#define MAX_DESC_SIZE 512
+#define MAX_DESC_TXBBS (MAX_DESC_SIZE / TXBB_SIZE)
+
+/*
+ * OS related constants and tunables
+ */
+
+#define MLX4_EN_WATCHDOG_TIMEOUT (15 * HZ)
+
+#define MLX4_EN_ALLOC_ORDER 2
+#define MLX4_EN_ALLOC_SIZE (PAGE_SIZE << MLX4_EN_ALLOC_ORDER)
+
+#define MLX4_EN_MAX_LRO_DESCRIPTORS 32
+
+/* Receive fragment sizes; we use at most 4 fragments (for 9600 byte MTU
+ * and 4K allocations) */
+enum {
+ FRAG_SZ0 = 512 - NET_IP_ALIGN,
+ FRAG_SZ1 = 1024,
+ FRAG_SZ2 = 4096,
+ FRAG_SZ3 = MLX4_EN_ALLOC_SIZE
+};
+#define MLX4_EN_MAX_RX_FRAGS 4
+
+/* 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)
+
+#define MLX4_EN_TX_RING_NUM 9
+#define MLX4_EN_DEF_TX_RING_SIZE 1024
+#define MLX4_EN_DEF_RX_RING_SIZE 1024
+
+/* Target number of bytes to coalesce with interrupt moderation */
+#define MLX4_EN_RX_COAL_TARGET 0x20000
+#define MLX4_EN_RX_COAL_TIME 0x10
+
+#define MLX4_EN_TX_COAL_PKTS 5
+#define MLX4_EN_TX_COAL_TIME 0x80
+
+#define MLX4_EN_RX_RATE_LOW 400000
+#define MLX4_EN_RX_COAL_TIME_LOW 0
+#define MLX4_EN_RX_RATE_HIGH 450000
+#define MLX4_EN_RX_COAL_TIME_HIGH 128
+#define MLX4_EN_RX_SIZE_THRESH 1024
+#define MLX4_EN_RX_RATE_THRESH (1000000 / MLX4_EN_RX_COAL_TIME_HIGH)
+#define MLX4_EN_SAMPLE_INTERVAL 0
+
+#define MLX4_EN_AUTO_CONF 0xffff
+
+#define MLX4_EN_DEF_RX_PAUSE 1
+#define MLX4_EN_DEF_TX_PAUSE 1
+
+/* Interval between sucessive polls in the Tx routine when polling is used
+ instead of interrupts (in per-core Tx rings) - should be power of 2 */
+#define MLX4_EN_TX_POLL_MODER 16
+#define MLX4_EN_TX_POLL_TIMEOUT (HZ / 4)
+
+#define ETH_LLC_SNAP_SIZE 8
+
+#define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN)
+#define HEADER_COPY_SIZE (128 - NET_IP_ALIGN)
+
+#define MLX4_EN_MIN_MTU 46
+#define ETH_BCAST 0xffffffffffffULL
+
+#ifdef MLX4_EN_PERF_STAT
+/* Number of samples to 'average' */
+#define AVG_SIZE 128
+#define AVG_FACTOR 1024
+#define NUM_PERF_STATS NUM_PERF_COUNTERS
+
+#define INC_PERF_COUNTER(cnt) (++(cnt))
+#define ADD_PERF_COUNTER(cnt, add) ((cnt) += (add))
+#define AVG_PERF_COUNTER(cnt, sample) \
+ ((cnt) = ((cnt) * (AVG_SIZE - 1) + (sample) * AVG_FACTOR) / AVG_SIZE)
+#define GET_PERF_COUNTER(cnt) (cnt)
+#define GET_AVG_PERF_COUNTER(cnt) ((cnt) / AVG_FACTOR)
+
+#else
+
+#define NUM_PERF_STATS 0
+#define INC_PERF_COUNTER(cnt) do {} while (0)
+#define ADD_PERF_COUNTER(cnt, add) do {} while (0)
+#define AVG_PERF_COUNTER(cnt, sample) do {} while (0)
+#define GET_PERF_COUNTER(cnt) (0)
+#define GET_AVG_PERF_COUNTER(cnt) (0)
+#endif /* MLX4_EN_PERF_STAT */
+
+/*
+ * Configurables
+ */
+
+enum cq_type {
+ RX = 0,
+ TX = 1,
+};
+
+
+/*
+ * Useful macros
+ */
+#define ROUNDUP_LOG2(x) ilog2(roundup_pow_of_two(x))
+#define XNOR(x, y) (!(x) == !(y))
+#define ILLEGAL_MAC(addr) (addr == 0xffffffffffffULL || addr == 0x0)
+
+
+struct mlx4_en_tx_info {
+ struct sk_buff *skb;
+ u32 nr_txbb;
+ u8 linear;
+ u8 data_offset;
+};
+
+
+#define MLX4_EN_BIT_DESC_OWN 0x80000000
+#define CTRL_SIZE sizeof(struct mlx4_wqe_ctrl_seg)
+#define MLX4_EN_MEMTYPE_PAD 0x100
+#define DS_SIZE sizeof(struct mlx4_wqe_data_seg)
+
+
+struct mlx4_en_tx_desc {
+ struct mlx4_wqe_ctrl_seg ctrl;
+ union {
+ struct mlx4_wqe_data_seg data; /* at least one data segment */
+ struct mlx4_wqe_lso_seg lso;
+ struct mlx4_wqe_inline_seg inl;
+ };
+};
+
+#define MLX4_EN_USE_SRQ 0x01000000
+
+struct mlx4_en_rx_alloc {
+ struct page *page;
+ u16 offset;
+};
+
+struct mlx4_en_tx_ring {
+ struct mlx4_hwq_resources wqres;
+ u32 size ; /* number of TXBBs */
+ u32 size_mask;
+ u16 stride;
+ u16 cqn; /* index of port CQ associated with this ring */
+ u32 prod;
+ u32 cons;
+ u32 buf_size;
+ u32 doorbell_qpn;
+ void *buf;
+ u16 poll_cnt;
+ int blocked;
+ struct mlx4_en_tx_info *tx_info;
+ u8 *bounce_buf;
+ u32 last_nr_txbb;
+ struct mlx4_qp qp;
+ struct mlx4_qp_context context;
+ int qpn;
+ enum mlx4_qp_state qp_state;
+ struct mlx4_srq dummy;
+ unsigned long bytes;
+ unsigned long packets;
+ spinlock_t comp_lock;
+};
+
+struct mlx4_en_rx_desc {
+ struct mlx4_wqe_srq_next_seg next;
+ /* actual number of entries depends on rx ring stride */
+ struct mlx4_wqe_data_seg data[0];
+};
+
+struct mlx4_en_rx_ring {
+ struct mlx4_srq srq;
+ struct mlx4_hwq_resources wqres;
+ struct mlx4_en_rx_alloc page_alloc[MLX4_EN_MAX_RX_FRAGS];
+ struct net_lro_mgr lro;
+ u32 size ; /* number of Rx descs*/
+ u32 actual_size;
+ u32 size_mask;
+ u16 stride;
+ u16 log_stride;
+ u16 cqn; /* index of port CQ associated with this ring */
+ u32 prod;
+ u32 cons;
+ u32 buf_size;
+ int need_refill;
+ int full;
+ void *buf;
+ void *rx_info;
+ unsigned long bytes;
+ unsigned long packets;
+};
+
+
+static inline int mlx4_en_can_lro(__be16 status)
+{
+ return (status & cpu_to_be16(MLX4_CQE_STATUS_IPV4 |
+ MLX4_CQE_STATUS_IPV4F |
+ MLX4_CQE_STATUS_IPV6 |
+ MLX4_CQE_STATUS_IPV4OPT |
+ MLX4_CQE_STATUS_TCP |
+ MLX4_CQE_STATUS_UDP |
+ MLX4_CQE_STATUS_IPOK)) ==
+ cpu_to_be16(MLX4_CQE_STATUS_IPV4 |
+ MLX4_CQE_STATUS_IPOK |
+ MLX4_CQE_STATUS_TCP);
+}
+
+struct mlx4_en_cq {
+ struct mlx4_cq mcq;
+ struct mlx4_hwq_resources wqres;
+ int ring;
+ spinlock_t lock;
+ struct net_device *dev;
+ struct napi_struct napi;
+ /* Per-core Tx cq processing support */
+ struct timer_list timer;
+ int size;
+ int buf_size;
+ unsigned vector;
+ enum cq_type is_tx;
+ u16 moder_time;
+ u16 moder_cnt;
+ int armed;
+ struct mlx4_cqe *buf;
+#define MLX4_EN_OPCODE_ERROR 0x1e
+};
+
+struct mlx4_en_port_profile {
+ u32 flags;
+ u32 tx_ring_num;
+ u32 rx_ring_num;
+ u32 tx_ring_size;
+ u32 rx_ring_size;
+};
+
+struct mlx4_en_profile {
+ int rss_xor;
+ int num_lro;
+ u8 rss_mask;
+ u32 active_ports;
+ u32 small_pkt_int;
+ int rx_moder_cnt;
+ int rx_moder_time;
+ int auto_moder;
+ u8 rx_pause;
+ u8 rx_ppp;
+ u8 tx_pause;
+ u8 tx_ppp;
+ u8 no_reset;
+ struct mlx4_en_port_profile prof[MLX4_MAX_PORTS + 1];
+};
+
+struct mlx4_en_dev {
+ struct mlx4_dev *dev;
+ struct pci_dev *pdev;
+ struct mutex state_lock;
+ struct net_device *pndev[MLX4_MAX_PORTS + 1];
+ u32 port_cnt;
+ bool device_up;
+ struct mlx4_en_profile profile;
+ u32 LSO_support;
+ struct workqueue_struct *workqueue;
+ struct device *dma_device;
+ void __iomem *uar_map;
+ struct mlx4_uar priv_uar;
+ struct mlx4_mr mr;
+ u32 priv_pdn;
+ spinlock_t uar_lock;
+};
+
+
+struct mlx4_en_rss_map {
+ int size;
+ int base_qpn;
+ u16 map[MAX_RSS_MAP_SIZE];
+ struct mlx4_qp qps[MAX_RSS_MAP_SIZE];
+ enum mlx4_qp_state state[MAX_RSS_MAP_SIZE];
+ struct mlx4_qp indir_qp;
+ enum mlx4_qp_state indir_state;
+};
+
+struct mlx4_en_rss_context {
+ __be32 base_qpn;
+ __be32 default_qpn;
+ u16 reserved;
+ u8 hash_fn;
+ u8 flags;
+ __be32 rss_key[10];
+};
+
+struct mlx4_en_pkt_stats {
+ unsigned long broadcast;
+ unsigned long rx_prio[8];
+ unsigned long tx_prio[8];
+#define NUM_PKT_STATS 17
+};
+
+struct mlx4_en_port_stats {
+ unsigned long lro_aggregated;
+ unsigned long lro_flushed;
+ unsigned long lro_no_desc;
+ unsigned long tso_packets;
+ unsigned long queue_stopped;
+ unsigned long wake_queue;
+ unsigned long tx_timeout;
+ unsigned long rx_alloc_failed;
+ unsigned long rx_chksum_good;
+ unsigned long rx_chksum_none;
+ unsigned long tx_chksum_offload;
+#define NUM_PORT_STATS 11
+};
+
+struct mlx4_en_perf_stats {
+ u32 tx_poll;
+ u64 tx_pktsz_avg;
+ u32 inflight_avg;
+ u16 tx_coal_avg;
+ u16 rx_coal_avg;
+ u32 napi_quota;
+#define NUM_PERF_COUNTERS 6
+};
+
+struct mlx4_en_frag_info {
+ u16 frag_size;
+ u16 frag_prefix_size;
+ u16 frag_stride;
+ u16 frag_align;
+ u16 last_offset;
+
+};
+
+struct mlx4_en_priv {
+ struct mlx4_en_dev *mdev;
+ struct mlx4_en_port_profile *prof;
+ struct net_device *dev;
+ struct vlan_group *vlgrp;
+ struct net_device_stats stats;
+ struct net_device_stats ret_stats;
+ spinlock_t stats_lock;
+
+ unsigned long last_moder_packets;
+ unsigned long last_moder_tx_packets;
+ unsigned long last_moder_bytes;
+ unsigned long last_moder_jiffies;
+ int last_moder_time;
+ u16 rx_usecs;
+ u16 rx_frames;
+ u16 tx_usecs;
+ u16 tx_frames;
+ u32 pkt_rate_low;
+ u16 rx_usecs_low;
+ u32 pkt_rate_high;
+ u16 rx_usecs_high;
+ u16 sample_interval;
+ u16 adaptive_rx_coal;
+ u32 msg_enable;
+
+ struct mlx4_hwq_resources res;
+ int link_state;
+ int last_link_state;
+ bool port_up;
+ int port;
+ int registered;
+ int allocated;
+ int stride;
+ int rx_csum;
+ u64 mac;
+ int mac_index;
+ unsigned max_mtu;
+ int base_qpn;
+
+ struct mlx4_en_rss_map rss_map;
+ u16 tx_prio_map[8];
+ u32 flags;
+#define MLX4_EN_FLAG_PROMISC 0x1
+ u32 tx_ring_num;
+ u32 rx_ring_num;
+ u32 rx_skb_size;
+ struct mlx4_en_frag_info frag_info[MLX4_EN_MAX_RX_FRAGS];
+ u16 num_frags;
+ u16 log_rx_info;
+
+ struct mlx4_en_tx_ring tx_ring[MAX_TX_RINGS];
+ struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS];
+ struct mlx4_en_cq tx_cq[MAX_TX_RINGS];
+ struct mlx4_en_cq rx_cq[MAX_RX_RINGS];
+ struct work_struct mcast_task;
+ struct work_struct mac_task;
+ struct delayed_work refill_task;
+ struct work_struct watchdog_task;
+ struct work_struct linkstate_task;
+ struct delayed_work stats_task;
+ struct mlx4_en_perf_stats pstats;
+ struct mlx4_en_pkt_stats pkstats;
+ struct mlx4_en_port_stats port_stats;
+ struct dev_mc_list *mc_list;
+ struct mlx4_en_stat_out_mbox hw_stats;
+};
+
+
+void mlx4_en_destroy_netdev(struct net_device *dev);
+int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
+ struct mlx4_en_port_profile *prof);
+
+int mlx4_en_get_profile(struct mlx4_en_dev *mdev);
+
+int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
+ int entries, int ring, enum cq_type mode);
+void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
+int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
+void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
+int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
+int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
+
+void mlx4_en_poll_tx_cq(unsigned long data);
+void mlx4_en_tx_irq(struct mlx4_cq *mcq);
+int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev);
+
+int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring,
+ u32 size, u16 stride);
+void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring);
+int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring,
+ int cq, int srqn);
+void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring);
+
+int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring,
+ u32 size, u16 stride);
+void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring);
+int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv);
+void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring);
+int mlx4_en_process_rx_cq(struct net_device *dev,
+ struct mlx4_en_cq *cq,
+ int budget);
+int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget);
+void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
+ int is_tx, int rss, int qpn, int cqn, int srqn,
+ struct mlx4_qp_context *context);
+int mlx4_en_map_buffer(struct mlx4_buf *buf);
+void mlx4_en_unmap_buffer(struct mlx4_buf *buf);
+
+void mlx4_en_calc_rx_buf(struct net_device *dev);
+void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv,
+ struct mlx4_en_rss_map *rss_map,
+ int num_entries, int num_rings);
+void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num);
+int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv);
+void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv);
+int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring);
+void mlx4_en_rx_refill(struct work_struct *work);
+void mlx4_en_rx_irq(struct mlx4_cq *mcq);
+
+int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mode);
+int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, u8 port, struct vlan_group *grp);
+int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
+ u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx);
+int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
+ u8 promisc);
+
+int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset);
+
+/*
+ * Globals
+ */
+extern const struct ethtool_ops mlx4_en_ethtool_ops;
+#endif
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index d1dd5b48dbd..0caf74cae8b 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -461,7 +461,7 @@ int mlx4_init_mr_table(struct mlx4_dev *dev)
int err;
err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts,
- ~0, dev->caps.reserved_mrws);
+ ~0, dev->caps.reserved_mrws, 0);
if (err)
return err;
diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c
index aa616892d09..26d1a7a9e37 100644
--- a/drivers/net/mlx4/pd.c
+++ b/drivers/net/mlx4/pd.c
@@ -62,7 +62,7 @@ int mlx4_init_pd_table(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
return mlx4_bitmap_init(&priv->pd_bitmap, dev->caps.num_pds,
- (1 << 24) - 1, dev->caps.reserved_pds);
+ (1 << 24) - 1, dev->caps.reserved_pds, 0);
}
void mlx4_cleanup_pd_table(struct mlx4_dev *dev)
@@ -100,7 +100,7 @@ int mlx4_init_uar_table(struct mlx4_dev *dev)
return mlx4_bitmap_init(&mlx4_priv(dev)->uar_table.bitmap,
dev->caps.num_uars, dev->caps.num_uars - 1,
- max(128, dev->caps.reserved_uars));
+ max(128, dev->caps.reserved_uars), 0);
}
void mlx4_cleanup_uar_table(struct mlx4_dev *dev)
diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c
new file mode 100644
index 00000000000..e2fdab42c4c
--- /dev/null
+++ b/drivers/net/mlx4/port.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/errno.h>
+#include <linux/if_ether.h>
+
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4.h"
+
+#define MLX4_MAC_VALID (1ull << 63)
+#define MLX4_MAC_MASK 0xffffffffffffULL
+
+#define MLX4_VLAN_VALID (1u << 31)
+#define MLX4_VLAN_MASK 0xfff
+
+void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
+{
+ int i;
+
+ mutex_init(&table->mutex);
+ for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
+ table->entries[i] = 0;
+ table->refs[i] = 0;
+ }
+ table->max = 1 << dev->caps.log_num_macs;
+ table->total = 0;
+}
+
+void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
+{
+ int i;
+
+ mutex_init(&table->mutex);
+ for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
+ table->entries[i] = 0;
+ table->refs[i] = 0;
+ }
+ table->max = 1 << dev->caps.log_num_vlans;
+ table->total = 0;
+}
+
+static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
+ __be64 *entries)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ u32 in_mod;
+ int err;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
+
+ in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
+ err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
+ MLX4_CMD_TIME_CLASS_B);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+
+int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index)
+{
+ struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table;
+ int i, err = 0;
+ int free = -1;
+
+ mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac);
+ mutex_lock(&table->mutex);
+ for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) {
+ if (free < 0 && !table->refs[i]) {
+ free = i;
+ continue;
+ }
+
+ if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
+ /* MAC already registered, increase refernce count */
+ *index = i;
+ ++table->refs[i];
+ goto out;
+ }
+ }
+ mlx4_dbg(dev, "Free MAC index is %d\n", free);
+
+ if (table->total == table->max) {
+ /* No free mac entries */
+ err = -ENOSPC;
+ goto out;
+ }
+
+ /* Register new MAC */
+ table->refs[free] = 1;
+ table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
+
+ err = mlx4_set_port_mac_table(dev, port, table->entries);
+ if (unlikely(err)) {
+ mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) mac);
+ table->refs[free] = 0;
+ table->entries[free] = 0;
+ goto out;
+ }
+
+ *index = free;
+ ++table->total;
+out:
+ mutex_unlock(&table->mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_register_mac);
+
+void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index)
+{
+ struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table;
+
+ mutex_lock(&table->mutex);
+ if (!table->refs[index]) {
+ mlx4_warn(dev, "No MAC entry for index %d\n", index);
+ goto out;
+ }
+ if (--table->refs[index]) {
+ mlx4_warn(dev, "Have more references for index %d,"
+ "no need to modify MAC table\n", index);
+ goto out;
+ }
+ table->entries[index] = 0;
+ mlx4_set_port_mac_table(dev, port, table->entries);
+ --table->total;
+out:
+ mutex_unlock(&table->mutex);
+}
+EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
+
+static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
+ __be32 *entries)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ u32 in_mod;
+ int err;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
+ in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
+ err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
+ MLX4_CMD_TIME_CLASS_B);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+
+ return err;
+}
+
+int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
+{
+ struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
+ int i, err = 0;
+ int free = -1;
+
+ mutex_lock(&table->mutex);
+ for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
+ if (free < 0 && (table->refs[i] == 0)) {
+ free = i;
+ continue;
+ }
+
+ if (table->refs[i] &&
+ (vlan == (MLX4_VLAN_MASK &
+ be32_to_cpu(table->entries[i])))) {
+ /* Vlan already registered, increase refernce count */
+ *index = i;
+ ++table->refs[i];
+ goto out;
+ }
+ }
+
+ if (table->total == table->max) {
+ /* No free vlan entries */
+ err = -ENOSPC;
+ goto out;
+ }
+
+ /* Register new MAC */
+ table->refs[free] = 1;
+ table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
+
+ err = mlx4_set_port_vlan_table(dev, port, table->entries);
+ if (unlikely(err)) {
+ mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
+ table->refs[free] = 0;
+ table->entries[free] = 0;
+ goto out;
+ }
+
+ *index = free;
+ ++table->total;
+out:
+ mutex_unlock(&table->mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_register_vlan);
+
+void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
+{
+ struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
+
+ if (index < MLX4_VLAN_REGULAR) {
+ mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
+ return;
+ }
+
+ mutex_lock(&table->mutex);
+ if (!table->refs[index]) {
+ mlx4_warn(dev, "No vlan entry for index %d\n", index);
+ goto out;
+ }
+ if (--table->refs[index]) {
+ mlx4_dbg(dev, "Have more references for index %d,"
+ "no need to modify vlan table\n", index);
+ goto out;
+ }
+ table->entries[index] = 0;
+ mlx4_set_port_vlan_table(dev, port, table->entries);
+ --table->total;
+out:
+ mutex_unlock(&table->mutex);
+}
+EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
+
+int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ int err;
+ u8 is_eth = dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ memset(mailbox->buf, 0, 256);
+ if (is_eth) {
+ ((u8 *) mailbox->buf)[3] = 6;
+ ((__be16 *) mailbox->buf)[4] = cpu_to_be16(1 << 15);
+ ((__be16 *) mailbox->buf)[6] = cpu_to_be16(1 << 15);
+ }
+ err = mlx4_cmd(dev, mailbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
+ MLX4_CMD_TIME_CLASS_B);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index c49a86044bf..1c565ef8d17 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -147,19 +147,42 @@ int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
}
EXPORT_SYMBOL_GPL(mlx4_qp_modify);
-int mlx4_qp_alloc(struct mlx4_dev *dev, int sqpn, struct mlx4_qp *qp)
+int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_qp_table *qp_table = &priv->qp_table;
+ int qpn;
+
+ qpn = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align);
+ if (qpn == -1)
+ return -ENOMEM;
+
+ *base = qpn;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range);
+
+void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_qp_table *qp_table = &priv->qp_table;
+ if (base_qpn < dev->caps.sqp_start + 8)
+ return;
+
+ mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt);
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_release_range);
+
+int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_qp_table *qp_table = &priv->qp_table;
int err;
- if (sqpn)
- qp->qpn = sqpn;
- else {
- qp->qpn = mlx4_bitmap_alloc(&qp_table->bitmap);
- if (qp->qpn == -1)
- return -ENOMEM;
- }
+ if (!qpn)
+ return -EINVAL;
+
+ qp->qpn = qpn;
err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn);
if (err)
@@ -208,9 +231,6 @@ err_put_qp:
mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
err_out:
- if (!sqpn)
- mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
-
return err;
}
EXPORT_SYMBOL_GPL(mlx4_qp_alloc);
@@ -239,9 +259,6 @@ void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp)
mlx4_table_put(dev, &qp_table->altc_table, qp->qpn);
mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
-
- if (qp->qpn >= dev->caps.sqp_start + 8)
- mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
}
EXPORT_SYMBOL_GPL(mlx4_qp_free);
@@ -255,6 +272,7 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
{
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
int err;
+ int reserved_from_top = 0;
spin_lock_init(&qp_table->lock);
INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC);
@@ -264,9 +282,40 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
* block of special QPs must be aligned to a multiple of 8, so
* round up.
*/
- dev->caps.sqp_start = ALIGN(dev->caps.reserved_qps, 8);
+ dev->caps.sqp_start =
+ ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8);
+
+ {
+ int sort[MLX4_NUM_QP_REGION];
+ int i, j, tmp;
+ int last_base = dev->caps.num_qps;
+
+ for (i = 1; i < MLX4_NUM_QP_REGION; ++i)
+ sort[i] = i;
+
+ for (i = MLX4_NUM_QP_REGION; i > 0; --i) {
+ for (j = 2; j < i; ++j) {
+ if (dev->caps.reserved_qps_cnt[sort[j]] >
+ dev->caps.reserved_qps_cnt[sort[j - 1]]) {
+ tmp = sort[j];
+ sort[j] = sort[j - 1];
+ sort[j - 1] = tmp;
+ }
+ }
+ }
+
+ for (i = 1; i < MLX4_NUM_QP_REGION; ++i) {
+ last_base -= dev->caps.reserved_qps_cnt[sort[i]];
+ dev->caps.reserved_qps_base[sort[i]] = last_base;
+ reserved_from_top +=
+ dev->caps.reserved_qps_cnt[sort[i]];
+ }
+
+ }
+
err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps,
- (1 << 24) - 1, dev->caps.sqp_start + 8);
+ (1 << 23) - 1, dev->caps.sqp_start + 8,
+ reserved_from_top);
if (err)
return err;
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c
index 533eb6db24b..fe9f218691f 100644
--- a/drivers/net/mlx4/srq.c
+++ b/drivers/net/mlx4/srq.c
@@ -245,7 +245,7 @@ int mlx4_init_srq_table(struct mlx4_dev *dev)
INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC);
err = mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs,
- dev->caps.num_srqs - 1, dev->caps.reserved_srqs);
+ dev->caps.num_srqs - 1, dev->caps.reserved_srqs, 0);
if (err)
return err;
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index b39d1cc1ef0..a24bb68887a 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -1205,11 +1205,12 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
devno = 0;
ndev->dma = -1;
- ndev->irq = platform_get_irq(pdev, 0);
- if (ndev->irq < 0) {
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
ret = -ENODEV;
goto out_release;
}
+ ndev->irq = ret;
SET_NETDEV_DEV(ndev, &pdev->dev);
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 22c17bbacb6..466a89e2444 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -456,7 +456,7 @@ static void catc_tx_timeout(struct net_device *netdev)
{
struct catc *catc = netdev_priv(netdev);
- warn("Transmit timed out.");
+ dev_warn(&netdev->dev, "Transmit timed out.\n");
usb_unlink_urb(catc->tx_urb);
}
@@ -847,7 +847,8 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
dbg("64k Memory\n");
break;
default:
- warn("Couldn't detect memory size, assuming 32k");
+ dev_warn(&intf->dev,
+ "Couldn't detect memory size, assuming 32k\n");
case 0x87654321:
catc_set_reg(catc, TxBufCount, 4);
catc_set_reg(catc, RxBufCount, 16);
@@ -953,7 +954,8 @@ static int __init catc_init(void)
{
int result = usb_register(&catc_driver);
if (result == 0)
- info(DRIVER_VERSION " " DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return result;
}
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index d6829db51b4..fdbf3be24fd 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -832,7 +832,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
{
- warn("kaweth failed tx_urb %d", res);
+ dev_warn(&net->dev, "kaweth failed tx_urb %d\n", res);
skip:
kaweth->stats.tx_errors++;
@@ -924,7 +924,7 @@ static void kaweth_tx_timeout(struct net_device *net)
{
struct kaweth_device *kaweth = netdev_priv(net);
- warn("%s: Tx timed out. Resetting.", net->name);
+ dev_warn(&net->dev, "%s: Tx timed out. Resetting.\n", net->name);
kaweth->stats.tx_errors++;
net->trans_start = jiffies;
@@ -1016,10 +1016,10 @@ static int kaweth_probe(
*/
if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) {
- info("Firmware present in device.");
+ dev_info(&intf->dev, "Firmware present in device.\n");
} else {
/* Download the firmware */
- info("Downloading firmware...");
+ dev_info(&intf->dev, "Downloading firmware...\n");
kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL);
if ((result = kaweth_download_firmware(kaweth,
"kaweth/new_code.bin",
@@ -1061,7 +1061,7 @@ static int kaweth_probe(
}
/* Device will now disappear for a moment... */
- info("Firmware loaded. I'll be back...");
+ dev_info(&intf->dev, "Firmware loaded. I'll be back...\n");
err_fw:
free_page((unsigned long)kaweth->firmware_buf);
free_netdev(netdev);
@@ -1075,10 +1075,10 @@ err_fw:
goto err_free_netdev;
}
- info("Statistics collection: %x", kaweth->configuration.statistics_mask);
- info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
- info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
- info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+ dev_info(&intf->dev, "Statistics collection: %x\n", kaweth->configuration.statistics_mask);
+ dev_info(&intf->dev, "Multicast filter limit: %x\n", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
+ dev_info(&intf->dev, "MTU: %d\n", le16_to_cpu(kaweth->configuration.segment_size));
+ dev_info(&intf->dev, "Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
(int)kaweth->configuration.hw_addr[0],
(int)kaweth->configuration.hw_addr[1],
(int)kaweth->configuration.hw_addr[2],
@@ -1174,7 +1174,8 @@ err_fw:
goto err_intfdata;
}
- info("kaweth interface created at %s", kaweth->net->name);
+ dev_info(&intf->dev, "kaweth interface created at %s\n",
+ kaweth->net->name);
dbg("Kaweth probe returning.");
@@ -1205,11 +1206,11 @@ static void kaweth_disconnect(struct usb_interface *intf)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
struct net_device *netdev;
- info("Unregistering");
+ dev_info(&intf->dev, "Unregistering\n");
usb_set_intfdata(intf, NULL);
if (!kaweth) {
- warn("unregistering non-existant device");
+ dev_warn(&intf->dev, "unregistering non-existant device\n");
return;
}
netdev = kaweth->net;
@@ -1269,7 +1270,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
if (!wait_event_timeout(awd.wqh, awd.done, timeout)) {
// timeout
- warn("usb_control/bulk_msg: timeout");
+ dev_warn(&urb->dev->dev, "usb_control/bulk_msg: timeout\n");
usb_kill_urb(urb); // remove urb safely
status = -ETIMEDOUT;
}
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 38b90e7a7ed..7914867110e 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -168,7 +168,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
netif_device_detach(pegasus->net);
if (netif_msg_drv(pegasus) && printk_ratelimit())
dev_err(&pegasus->intf->dev, "%s, status %d\n",
- __FUNCTION__, ret);
+ __func__, ret);
goto out;
}
@@ -192,7 +192,7 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
if (!buffer) {
if (netif_msg_drv(pegasus))
dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
memcpy(buffer, data, size);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index df56a518691..6133401ebc6 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -221,7 +221,7 @@ static void ctrl_callback(struct urb *urb)
case -ENOENT:
break;
default:
- warn("ctrl urb status %d", urb->status);
+ dev_warn(&urb->dev->dev, "ctrl urb status %d\n", urb->status);
}
dev = urb->context;
clear_bit(RX_REG_SET, &dev->flags);
@@ -441,10 +441,10 @@ static void read_bulk_callback(struct urb *urb)
case -ENOENT:
return; /* the urb is in unlink state */
case -ETIME:
- warn("may be reset is needed?..");
+ dev_warn(&urb->dev->dev, "may be reset is needed?..\n");
goto goon;
default:
- warn("Rx status %d", urb->status);
+ dev_warn(&urb->dev->dev, "Rx status %d\n", urb->status);
goto goon;
}
@@ -538,7 +538,8 @@ static void write_bulk_callback(struct urb *urb)
if (!netif_device_present(dev->netdev))
return;
if (urb->status)
- info("%s: Tx status %d", dev->netdev->name, urb->status);
+ dev_info(&urb->dev->dev, "%s: Tx status %d\n",
+ dev->netdev->name, urb->status);
dev->netdev->trans_start = jiffies;
netif_wake_queue(dev->netdev);
}
@@ -561,7 +562,8 @@ static void intr_callback(struct urb *urb)
return;
/* -EPIPE: should clear the halt */
default:
- info("%s: intr status %d", dev->netdev->name, urb->status);
+ dev_info(&urb->dev->dev, "%s: intr status %d\n",
+ dev->netdev->name, urb->status);
goto resubmit;
}
@@ -665,7 +667,7 @@ static int enable_net_traffic(rtl8150_t * dev)
u8 cr, tcr, rcr, msr;
if (!rtl8150_reset(dev)) {
- warn("%s - device reset failed", __FUNCTION__);
+ dev_warn(&dev->udev->dev, "device reset failed\n");
}
/* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */
rcr = 0x9e;
@@ -699,7 +701,7 @@ static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
static void rtl8150_tx_timeout(struct net_device *netdev)
{
rtl8150_t *dev = netdev_priv(netdev);
- warn("%s: Tx timeout.", netdev->name);
+ dev_warn(&netdev->dev, "Tx timeout.\n");
usb_unlink_urb(dev->tx_urb);
dev->stats.tx_errors++;
}
@@ -710,12 +712,12 @@ static void rtl8150_set_multicast(struct net_device *netdev)
netif_stop_queue(netdev);
if (netdev->flags & IFF_PROMISC) {
dev->rx_creg |= cpu_to_le16(0x0001);
- info("%s: promiscuous mode", netdev->name);
+ dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name);
} else if (netdev->mc_count ||
(netdev->flags & IFF_ALLMULTI)) {
dev->rx_creg &= cpu_to_le16(0xfffe);
dev->rx_creg |= cpu_to_le16(0x0002);
- info("%s: allmulti set", netdev->name);
+ dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name);
} else {
/* ~RX_MULTICAST, ~RX_PROMISCUOUS */
dev->rx_creg &= cpu_to_le16(0x00fc);
@@ -740,7 +742,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
if (res == -ENODEV)
netif_device_detach(dev->netdev);
else {
- warn("failed tx_urb %d\n", res);
+ dev_warn(&netdev->dev, "failed tx_urb %d\n", res);
dev->stats.tx_errors++;
netif_start_queue(netdev);
}
@@ -783,7 +785,7 @@ static int rtl8150_open(struct net_device *netdev)
if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
if (res == -ENODEV)
netif_device_detach(dev->netdev);
- warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
+ dev_warn(&netdev->dev, "rx_urb submit failed: %d\n", res);
return res;
}
usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
@@ -792,7 +794,7 @@ static int rtl8150_open(struct net_device *netdev)
if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) {
if (res == -ENODEV)
netif_device_detach(dev->netdev);
- warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
+ dev_warn(&netdev->dev, "intr_urb submit failed: %d\n", res);
usb_kill_urb(dev->rx_urb);
return res;
}
@@ -947,7 +949,7 @@ static int rtl8150_probe(struct usb_interface *intf,
goto out2;
}
- info("%s: rtl8150 is detected", netdev->name);
+ dev_info(&intf->dev, "%s: rtl8150 is detected\n", netdev->name);
return 0;
@@ -984,7 +986,8 @@ static void rtl8150_disconnect(struct usb_interface *intf)
static int __init usb_rtl8150_init(void)
{
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return usb_register(&rtl8150_driver);
}
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index f972fef87c9..ee51b6a5e60 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -318,7 +318,7 @@ sbni_pci_probe( struct net_device *dev )
continue;
}
- if( pci_irq_line <= 0 || pci_irq_line >= NR_IRQS )
+ if (pci_irq_line <= 0 || pci_irq_line >= nr_irqs)
printk( KERN_WARNING " WARNING: The PCI BIOS assigned "
"this PCI card to IRQ %d, which is unlikely "
"to work!.\n"
diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c
new file mode 100644
index 00000000000..da42aa06a3b
--- /dev/null
+++ b/drivers/net/xtsonic.c
@@ -0,0 +1,319 @@
+/*
+ * xtsonic.c
+ *
+ * (C) 2001 - 2007 Tensilica Inc.
+ * Kevin Chea <kchea@yahoo.com>
+ * Marc Gauthier <marc@linux-xtensa.org>
+ * Chris Zankel <chris@zankel.net>
+ *
+ * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+ *
+ * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
+ *
+ * A driver for the onboard Sonic ethernet controller on the XT2000.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+
+static char xtsonic_string[] = "xtsonic";
+
+extern unsigned xtboard_nvram_valid(void);
+extern void xtboard_get_ether_addr(unsigned char *buf);
+
+#include "sonic.h"
+
+/*
+ * According to the documentation for the Sonic ethernet controller,
+ * EOBC should be 760 words (1520 bytes) for 32-bit applications, and,
+ * as such, 2 words less than the buffer size. The value for RBSIZE
+ * defined in sonic.h, however is only 1520.
+ *
+ * (Note that in 16-bit configurations, EOBC is 759 words (1518 bytes) and
+ * RBSIZE 1520 bytes)
+ */
+#undef SONIC_RBSIZE
+#define SONIC_RBSIZE 1524
+
+/*
+ * The chip provides 256 byte register space.
+ */
+#define SONIC_MEM_SIZE 0x100
+
+/*
+ * Macros to access SONIC registers
+ */
+#define SONIC_READ(reg) \
+ (0xffff & *((volatile unsigned int *)dev->base_addr+reg))
+
+#define SONIC_WRITE(reg,val) \
+ *((volatile unsigned int *)dev->base_addr+reg) = val
+
+
+/* Use 0 for production, 1 for verification, and >2 for debug */
+#ifdef SONIC_DEBUG
+static unsigned int sonic_debug = SONIC_DEBUG;
+#else
+static unsigned int sonic_debug = 1;
+#endif
+
+/*
+ * We cannot use station (ethernet) address prefixes to detect the
+ * sonic controller since these are board manufacturer depended.
+ * So we check for known Silicon Revision IDs instead.
+ */
+static unsigned short known_revisions[] =
+{
+ 0x101, /* SONIC 83934 */
+ 0xffff /* end of list */
+};
+
+static int xtsonic_open(struct net_device *dev)
+{
+ if (request_irq(dev->irq,&sonic_interrupt,IRQF_DISABLED,"sonic",dev)) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+ dev->name, dev->irq);
+ return -EAGAIN;
+ }
+ return sonic_open(dev);
+}
+
+static int xtsonic_close(struct net_device *dev)
+{
+ int err;
+ err = sonic_close(dev);
+ free_irq(dev->irq, dev);
+ return err;
+}
+
+static int __init sonic_probe1(struct net_device *dev)
+{
+ static unsigned version_printed = 0;
+ unsigned int silicon_revision;
+ struct sonic_local *lp = netdev_priv(dev);
+ unsigned int base_addr = dev->base_addr;
+ int i;
+ int err = 0;
+
+ if (!request_mem_region(base_addr, 0x100, xtsonic_string))
+ return -EBUSY;
+
+ /*
+ * get the Silicon Revision ID. If this is one of the known
+ * one assume that we found a SONIC ethernet controller at
+ * the expected location.
+ */
+ silicon_revision = SONIC_READ(SONIC_SR);
+ if (sonic_debug > 1)
+ printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
+
+ i = 0;
+ while ((known_revisions[i] != 0xffff) &&
+ (known_revisions[i] != silicon_revision))
+ i++;
+
+ if (known_revisions[i] == 0xffff) {
+ printk("SONIC ethernet controller not found (0x%4x)\n",
+ silicon_revision);
+ return -ENODEV;
+ }
+
+ if (sonic_debug && version_printed++ == 0)
+ printk(version);
+
+ /*
+ * Put the sonic into software reset, then retrieve ethernet address.
+ * Note: we are assuming that the boot-loader has initialized the cam.
+ */
+ SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
+ SONIC_WRITE(SONIC_DCR,
+ SONIC_DCR_WC0|SONIC_DCR_DW|SONIC_DCR_LBR|SONIC_DCR_SBUS);
+ SONIC_WRITE(SONIC_CEP,0);
+ SONIC_WRITE(SONIC_IMR,0);
+
+ SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
+ SONIC_WRITE(SONIC_CEP,0);
+
+ for (i=0; i<3; i++) {
+ unsigned int val = SONIC_READ(SONIC_CAP0-i);
+ dev->dev_addr[i*2] = val;
+ dev->dev_addr[i*2+1] = val >> 8;
+ }
+
+ /* Initialize the device structure. */
+
+ lp->dma_bitmode = SONIC_BITMODE32;
+
+ /*
+ * Allocate local private descriptor areas in uncached space.
+ * The entire structure must be located within the same 64kb segment.
+ * A simple way to ensure this is to allocate twice the
+ * size of the structure -- given that the structure is
+ * much less than 64 kB, at least one of the halves of
+ * the allocated area will be contained entirely in 64 kB.
+ * We also allocate extra space for a pointer to allow freeing
+ * this structure later on (in xtsonic_cleanup_module()).
+ */
+ lp->descriptors =
+ dma_alloc_coherent(lp->device,
+ SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+ &lp->descriptors_laddr, GFP_KERNEL);
+
+ if (lp->descriptors == NULL) {
+ printk(KERN_ERR "%s: couldn't alloc DMA memory for "
+ " descriptors.\n", lp->device->bus_id);
+ goto out;
+ }
+
+ lp->cda = lp->descriptors;
+ lp->tda = lp->cda + (SIZEOF_SONIC_CDA
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+ lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+ lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+
+ /* get the virtual dma address */
+
+ lp->cda_laddr = lp->descriptors_laddr;
+ lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+ lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+ lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+
+ dev->open = xtsonic_open;
+ dev->stop = xtsonic_close;
+ dev->hard_start_xmit = sonic_send_packet;
+ dev->get_stats = sonic_get_stats;
+ dev->set_multicast_list = &sonic_multicast_list;
+ dev->tx_timeout = sonic_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ /*
+ * clear tally counter
+ */
+ SONIC_WRITE(SONIC_CRCT,0xffff);
+ SONIC_WRITE(SONIC_FAET,0xffff);
+ SONIC_WRITE(SONIC_MPT,0xffff);
+
+ return 0;
+out:
+ release_region(dev->base_addr, SONIC_MEM_SIZE);
+ return err;
+}
+
+
+/*
+ * Probe for a SONIC ethernet controller on an XT2000 board.
+ * Actually probing is superfluous but we're paranoid.
+ */
+
+int __init xtsonic_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct sonic_local *lp;
+ struct resource *resmem, *resirq;
+ int err = 0;
+
+ DECLARE_MAC_BUF(mac);
+
+ if ((resmem = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == NULL)
+ return -ENODEV;
+
+ if ((resirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0)) == NULL)
+ return -ENODEV;
+
+ if ((dev = alloc_etherdev(sizeof(struct sonic_local))) == NULL)
+ return -ENOMEM;
+
+ lp = netdev_priv(dev);
+ lp->device = &pdev->dev;
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ netdev_boot_setup_check(dev);
+
+ dev->base_addr = resmem->start;
+ dev->irq = resirq->start;
+
+ if ((err = sonic_probe1(dev)))
+ goto out;
+ if ((err = register_netdev(dev)))
+ goto out1;
+
+ printk("%s: SONIC ethernet @%08lx, MAC %s, IRQ %d\n", dev->name,
+ dev->base_addr, print_mac(mac, dev->dev_addr), dev->irq);
+
+ return 0;
+
+out1:
+ release_region(dev->base_addr, SONIC_MEM_SIZE);
+out:
+ free_netdev(dev);
+
+ return err;
+}
+
+MODULE_DESCRIPTION("Xtensa XT2000 SONIC ethernet driver");
+module_param(sonic_debug, int, 0);
+MODULE_PARM_DESC(sonic_debug, "xtsonic debug level (1-4)");
+
+#include "sonic.c"
+
+static int __devexit xtsonic_device_remove (struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct sonic_local *lp = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ dma_free_coherent(lp->device,
+ SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+ lp->descriptors, lp->descriptors_laddr);
+ release_region (dev->base_addr, SONIC_MEM_SIZE);
+ free_netdev(dev);
+
+ return 0;
+}
+
+static struct platform_driver xtsonic_driver = {
+ .probe = xtsonic_probe,
+ .remove = __devexit_p(xtsonic_device_remove),
+ .driver = {
+ .name = xtsonic_string,
+ },
+};
+
+static int __init xtsonic_init(void)
+{
+ return platform_driver_register(&xtsonic_driver);
+}
+
+static void __exit xtsonic_cleanup(void)
+{
+ platform_driver_unregister(&xtsonic_driver);
+}
+
+module_init(xtsonic_init);
+module_exit(xtsonic_cleanup);
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index 6a98dc8aa30..24bbef777c1 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -41,7 +41,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
info.addr = *addr;
- request_module(info.type);
+ request_module("%s", info.type);
result = i2c_new_device(adap, &info);
if (result == NULL) {
diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c
index b01eec026f6..bed0ed6dcdc 100644
--- a/drivers/of/of_spi.c
+++ b/drivers/of/of_spi.c
@@ -61,6 +61,8 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
spi->mode |= SPI_CPHA;
if (of_find_property(nc, "spi-cpol", NULL))
spi->mode |= SPI_CPOL;
+ if (of_find_property(nc, "spi-cs-high", NULL))
+ spi->mode |= SPI_CS_HIGH;
/* Device speed */
prop = of_get_property(nc, "spi-max-frequency", &len);
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index ed982273fb8..b55cd23ffde 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -41,7 +41,6 @@ static cpumask_t marked_cpus = CPU_MASK_NONE;
static DEFINE_SPINLOCK(task_mortuary);
static void process_task_mortuary(void);
-
/* Take ownership of the task struct and place it on the
* list for processing. Only after two full buffer syncs
* does the task eventually get freed, because by then
@@ -341,7 +340,7 @@ static void add_trace_begin(void)
* Add IBS fetch and op entries to event buffer
*/
static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
- int in_kernel, struct mm_struct *mm)
+ struct mm_struct *mm)
{
unsigned long rip;
int i, count;
@@ -565,9 +564,11 @@ void sync_buffer(int cpu)
struct task_struct *new;
unsigned long cookie = 0;
int in_kernel = 1;
- unsigned int i;
sync_buffer_state state = sb_buffer_start;
+#ifndef CONFIG_OPROFILE_IBS
+ unsigned int i;
unsigned long available;
+#endif
mutex_lock(&buffer_mutex);
@@ -575,9 +576,13 @@ void sync_buffer(int cpu)
/* Remember, only we can modify tail_pos */
+#ifndef CONFIG_OPROFILE_IBS
available = get_slots(cpu_buf);
for (i = 0; i < available; ++i) {
+#else
+ while (get_slots(cpu_buf)) {
+#endif
struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos];
if (is_code(s->eip)) {
@@ -593,12 +598,10 @@ void sync_buffer(int cpu)
#ifdef CONFIG_OPROFILE_IBS
} else if (s->event == IBS_FETCH_BEGIN) {
state = sb_bt_start;
- add_ibs_begin(cpu_buf,
- IBS_FETCH_CODE, in_kernel, mm);
+ add_ibs_begin(cpu_buf, IBS_FETCH_CODE, mm);
} else if (s->event == IBS_OP_BEGIN) {
state = sb_bt_start;
- add_ibs_begin(cpu_buf,
- IBS_OP_CODE, in_kernel, mm);
+ add_ibs_begin(cpu_buf, IBS_OP_CODE, mm);
#endif
} else {
struct mm_struct *oldmm = mm;
@@ -628,3 +631,27 @@ void sync_buffer(int cpu)
mutex_unlock(&buffer_mutex);
}
+
+/* The function can be used to add a buffer worth of data directly to
+ * the kernel buffer. The buffer is assumed to be a circular buffer.
+ * Take the entries from index start and end at index end, wrapping
+ * at max_entries.
+ */
+void oprofile_put_buff(unsigned long *buf, unsigned int start,
+ unsigned int stop, unsigned int max)
+{
+ int i;
+
+ i = start;
+
+ mutex_lock(&buffer_mutex);
+ while (i != stop) {
+ add_event_entry(buf[i++]);
+
+ if (i >= max)
+ i = 0;
+ }
+
+ mutex_unlock(&buffer_mutex);
+}
+
diff --git a/drivers/oprofile/buffer_sync.h b/drivers/oprofile/buffer_sync.h
index 08866f6a96a..3110732c183 100644
--- a/drivers/oprofile/buffer_sync.h
+++ b/drivers/oprofile/buffer_sync.h
@@ -9,13 +9,13 @@
#ifndef OPROFILE_BUFFER_SYNC_H
#define OPROFILE_BUFFER_SYNC_H
-
+
/* add the necessary profiling hooks */
int sync_start(void);
/* remove the hooks */
void sync_stop(void);
-
+
/* sync the given CPU's buffer */
void sync_buffer(int cpu);
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index e1bd5a937f6..01d38e78cde 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -22,7 +22,7 @@
#include <linux/oprofile.h>
#include <linux/vmalloc.h>
#include <linux/errno.h>
-
+
#include "event_buffer.h"
#include "cpu_buffer.h"
#include "buffer_sync.h"
@@ -38,27 +38,40 @@ static int work_enabled;
void free_cpu_buffers(void)
{
int i;
-
- for_each_online_cpu(i) {
+
+ for_each_possible_cpu(i) {
vfree(per_cpu(cpu_buffer, i).buffer);
per_cpu(cpu_buffer, i).buffer = NULL;
}
}
+unsigned long oprofile_get_cpu_buffer_size(void)
+{
+ return fs_cpu_buffer_size;
+}
+
+void oprofile_cpu_buffer_inc_smpl_lost(void)
+{
+ struct oprofile_cpu_buffer *cpu_buf
+ = &__get_cpu_var(cpu_buffer);
+
+ cpu_buf->sample_lost_overflow++;
+}
+
int alloc_cpu_buffers(void)
{
int i;
-
+
unsigned long buffer_size = fs_cpu_buffer_size;
-
- for_each_online_cpu(i) {
+
+ for_each_possible_cpu(i) {
struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
-
+
b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size,
cpu_to_node(i));
if (!b->buffer)
goto fail;
-
+
b->last_task = NULL;
b->last_is_kernel = -1;
b->tracing = 0;
@@ -112,7 +125,7 @@ void end_cpu_work(void)
}
/* Resets the cpu buffer to a sane state. */
-void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf)
+void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf)
{
/* reset these to invalid values; the next sample
* collected will populate the buffer with proper
@@ -123,7 +136,7 @@ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf)
}
/* compute number of available slots in cpu_buffer queue */
-static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b)
+static unsigned long nr_available_slots(struct oprofile_cpu_buffer const *b)
{
unsigned long head = b->head_pos;
unsigned long tail = b->tail_pos;
@@ -134,7 +147,7 @@ static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b)
return tail + (b->buffer_size - head) - 1;
}
-static void increment_head(struct oprofile_cpu_buffer * b)
+static void increment_head(struct oprofile_cpu_buffer *b)
{
unsigned long new_head = b->head_pos + 1;
@@ -149,17 +162,17 @@ static void increment_head(struct oprofile_cpu_buffer * b)
}
static inline void
-add_sample(struct oprofile_cpu_buffer * cpu_buf,
- unsigned long pc, unsigned long event)
+add_sample(struct oprofile_cpu_buffer *cpu_buf,
+ unsigned long pc, unsigned long event)
{
- struct op_sample * entry = &cpu_buf->buffer[cpu_buf->head_pos];
+ struct op_sample *entry = &cpu_buf->buffer[cpu_buf->head_pos];
entry->eip = pc;
entry->event = event;
increment_head(cpu_buf);
}
static inline void
-add_code(struct oprofile_cpu_buffer * buffer, unsigned long value)
+add_code(struct oprofile_cpu_buffer *buffer, unsigned long value)
{
add_sample(buffer, ESCAPE_CODE, value);
}
@@ -173,10 +186,10 @@ add_code(struct oprofile_cpu_buffer * buffer, unsigned long value)
* 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,
+static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
int is_kernel, unsigned long event)
{
- struct task_struct * task;
+ struct task_struct *task;
cpu_buf->sample_received++;
@@ -205,7 +218,7 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
cpu_buf->last_task = task;
add_code(cpu_buf, (unsigned long)task);
}
-
+
add_sample(cpu_buf, pc, event);
return 1;
}
@@ -222,7 +235,7 @@ static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
return 1;
}
-static void oprofile_end_trace(struct oprofile_cpu_buffer * cpu_buf)
+static void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf)
{
cpu_buf->tracing = 0;
}
@@ -257,21 +270,23 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
#ifdef CONFIG_OPROFILE_IBS
-#define MAX_IBS_SAMPLE_SIZE 14
-static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf,
- unsigned long pc, int is_kernel, unsigned int *ibs, int ibs_code)
+#define MAX_IBS_SAMPLE_SIZE 14
+
+void oprofile_add_ibs_sample(struct pt_regs *const regs,
+ unsigned int *const ibs_sample, int ibs_code)
{
+ int is_kernel = !user_mode(regs);
+ struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
struct task_struct *task;
cpu_buf->sample_received++;
if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) {
+ /* we can't backtrace since we lost the source of this event */
cpu_buf->sample_lost_overflow++;
- return 0;
+ return;
}
- is_kernel = !!is_kernel;
-
/* notice a switch from user->kernel or vice versa */
if (cpu_buf->last_is_kernel != is_kernel) {
cpu_buf->last_is_kernel = is_kernel;
@@ -281,7 +296,6 @@ static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf,
/* notice a task switch */
if (!is_kernel) {
task = current;
-
if (cpu_buf->last_task != task) {
cpu_buf->last_task = task;
add_code(cpu_buf, (unsigned long)task);
@@ -289,36 +303,17 @@ static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf,
}
add_code(cpu_buf, ibs_code);
- add_sample(cpu_buf, ibs[0], ibs[1]);
- add_sample(cpu_buf, ibs[2], ibs[3]);
- add_sample(cpu_buf, ibs[4], ibs[5]);
+ add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]);
+ add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]);
+ add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]);
if (ibs_code == IBS_OP_BEGIN) {
- add_sample(cpu_buf, ibs[6], ibs[7]);
- add_sample(cpu_buf, ibs[8], ibs[9]);
- add_sample(cpu_buf, ibs[10], ibs[11]);
- }
-
- return 1;
-}
-
-void oprofile_add_ibs_sample(struct pt_regs *const regs,
- unsigned int * const ibs_sample, u8 code)
-{
- int is_kernel = !user_mode(regs);
- unsigned long pc = profile_pc(regs);
-
- struct oprofile_cpu_buffer *cpu_buf =
- &per_cpu(cpu_buffer, smp_processor_id());
-
- if (!backtrace_depth) {
- log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code);
- return;
+ add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]);
+ add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]);
+ add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]);
}
- /* if log_sample() fails we can't backtrace since we lost the source
- * of this event */
- if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code))
+ if (backtrace_depth)
oprofile_ops.backtrace(regs, backtrace_depth);
}
@@ -363,11 +358,16 @@ void oprofile_add_trace(unsigned long pc)
*/
static void wq_sync_buffer(struct work_struct *work)
{
- struct oprofile_cpu_buffer * b =
+ struct oprofile_cpu_buffer *b =
container_of(work, struct oprofile_cpu_buffer, work.work);
if (b->cpu != smp_processor_id()) {
printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n",
smp_processor_id(), b->cpu);
+
+ if (!cpu_online(b->cpu)) {
+ cancel_delayed_work(&b->work);
+ return;
+ }
}
sync_buffer(b->cpu);
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index 9c44d004da6..d3cc26264db 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -15,9 +15,9 @@
#include <linux/workqueue.h>
#include <linux/cache.h>
#include <linux/sched.h>
-
+
struct task_struct;
-
+
int alloc_cpu_buffers(void);
void free_cpu_buffers(void);
@@ -31,15 +31,15 @@ struct op_sample {
unsigned long eip;
unsigned long event;
};
-
+
struct oprofile_cpu_buffer {
volatile unsigned long head_pos;
volatile unsigned long tail_pos;
unsigned long buffer_size;
- struct task_struct * last_task;
+ struct task_struct *last_task;
int last_is_kernel;
int tracing;
- struct op_sample * buffer;
+ struct op_sample *buffer;
unsigned long sample_received;
unsigned long sample_lost_overflow;
unsigned long backtrace_aborted;
@@ -50,7 +50,7 @@ struct oprofile_cpu_buffer {
DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
-void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
+void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf);
/* transient events for the CPU buffer -> event buffer */
#define CPU_IS_KERNEL 1
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index 8d692a5c8e7..d962ba0dd87 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -19,16 +19,16 @@
#include <linux/dcookies.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
-
+
#include "oprof.h"
#include "event_buffer.h"
#include "oprofile_stats.h"
DEFINE_MUTEX(buffer_mutex);
-
+
static unsigned long buffer_opened;
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
-static unsigned long * event_buffer;
+static unsigned long *event_buffer;
static unsigned long buffer_size;
static unsigned long buffer_watershed;
static size_t buffer_pos;
@@ -66,7 +66,7 @@ void wake_up_buffer_waiter(void)
mutex_unlock(&buffer_mutex);
}
-
+
int alloc_event_buffer(void)
{
int err = -ENOMEM;
@@ -76,13 +76,13 @@ int alloc_event_buffer(void)
buffer_size = fs_buffer_size;
buffer_watershed = fs_buffer_watershed;
spin_unlock_irqrestore(&oprofilefs_lock, flags);
-
+
if (buffer_watershed >= buffer_size)
return -EINVAL;
-
+
event_buffer = vmalloc(sizeof(unsigned long) * buffer_size);
if (!event_buffer)
- goto out;
+ goto out;
err = 0;
out:
@@ -97,8 +97,8 @@ void free_event_buffer(void)
event_buffer = NULL;
}
-
-static int event_buffer_open(struct inode * inode, struct file * file)
+
+static int event_buffer_open(struct inode *inode, struct file *file)
{
int err = -EPERM;
@@ -116,14 +116,14 @@ static int event_buffer_open(struct inode * inode, struct file * file)
file->private_data = dcookie_register();
if (!file->private_data)
goto out;
-
+
if ((err = oprofile_setup()))
goto fail;
/* NB: the actual start happens from userspace
* echo 1 >/dev/oprofile/enable
*/
-
+
return 0;
fail:
@@ -134,7 +134,7 @@ out:
}
-static int event_buffer_release(struct inode * inode, struct file * file)
+static int event_buffer_release(struct inode *inode, struct file *file)
{
oprofile_stop();
oprofile_shutdown();
@@ -146,8 +146,8 @@ static int event_buffer_release(struct inode * inode, struct file * file)
}
-static ssize_t event_buffer_read(struct file * file, char __user * buf,
- size_t count, loff_t * offset)
+static ssize_t event_buffer_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
{
int retval = -EINVAL;
size_t const max = buffer_size * sizeof(unsigned long);
@@ -172,18 +172,18 @@ static ssize_t event_buffer_read(struct file * file, char __user * buf,
retval = -EFAULT;
count = buffer_pos * sizeof(unsigned long);
-
+
if (copy_to_user(buf, event_buffer, count))
goto out;
retval = count;
buffer_pos = 0;
-
+
out:
mutex_unlock(&buffer_mutex);
return retval;
}
-
+
const struct file_operations event_buffer_fops = {
.open = event_buffer_open,
.release = event_buffer_release,
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 5076ed1ebd8..4e70749f8d1 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -10,13 +10,20 @@
#ifndef EVENT_BUFFER_H
#define EVENT_BUFFER_H
-#include <linux/types.h>
+#include <linux/types.h>
#include <asm/mutex.h>
-
+
int alloc_event_buffer(void);
void free_event_buffer(void);
-
+
+/**
+ * Add data to the event buffer.
+ * The data passed is free-form, but typically consists of
+ * file offsets, dcookies, context information, and ESCAPE codes.
+ */
+void add_event_entry(unsigned long data);
+
/* wake up the process sleeping on the event file */
void wake_up_buffer_waiter(void);
@@ -24,10 +31,10 @@ void wake_up_buffer_waiter(void);
#define NO_COOKIE 0UL
extern const struct file_operations event_buffer_fops;
-
+
/* mutex between sync_cpu_buffers() and the
* file reading code.
*/
extern struct mutex buffer_mutex;
-
+
#endif /* EVENT_BUFFER_H */
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index 2c645170f06..cd375907f26 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -19,7 +19,7 @@
#include "cpu_buffer.h"
#include "buffer_sync.h"
#include "oprofile_stats.h"
-
+
struct oprofile_operations oprofile_ops;
unsigned long oprofile_started;
@@ -36,7 +36,7 @@ static int timer = 0;
int oprofile_setup(void)
{
int err;
-
+
mutex_lock(&start_mutex);
if ((err = alloc_cpu_buffers()))
@@ -44,10 +44,10 @@ int oprofile_setup(void)
if ((err = alloc_event_buffer()))
goto out1;
-
+
if (oprofile_ops.setup && (err = oprofile_ops.setup()))
goto out2;
-
+
/* Note even though this starts part of the
* profiling overhead, it's necessary to prevent
* us missing task deaths and eventually oopsing
@@ -74,7 +74,7 @@ post_sync:
is_setup = 1;
mutex_unlock(&start_mutex);
return 0;
-
+
out3:
if (oprofile_ops.shutdown)
oprofile_ops.shutdown();
@@ -92,17 +92,17 @@ out:
int oprofile_start(void)
{
int err = -EINVAL;
-
+
mutex_lock(&start_mutex);
-
+
if (!is_setup)
goto out;
- err = 0;
-
+ err = 0;
+
if (oprofile_started)
goto out;
-
+
oprofile_reset_stats();
if ((err = oprofile_ops.start()))
@@ -114,7 +114,7 @@ out:
return err;
}
-
+
/* echo 0>/dev/oprofile/enable */
void oprofile_stop(void)
{
@@ -204,13 +204,13 @@ static void __exit oprofile_exit(void)
oprofile_arch_exit();
}
-
+
module_init(oprofile_init);
module_exit(oprofile_exit);
module_param_named(timer, timer, int, 0644);
MODULE_PARM_DESC(timer, "force use of timer interrupt");
-
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Levon <levon@movementarian.org>");
MODULE_DESCRIPTION("OProfile system profiler");
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h
index 18323650806..5df0c21a608 100644
--- a/drivers/oprofile/oprof.h
+++ b/drivers/oprofile/oprof.h
@@ -11,7 +11,7 @@
#define OPROF_H
int oprofile_setup(void);
-void oprofile_shutdown(void);
+void oprofile_shutdown(void);
int oprofilefs_register(void);
void oprofilefs_unregister(void);
@@ -20,20 +20,20 @@ int oprofile_start(void);
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 struct oprofile_operations oprofile_ops;
extern unsigned long oprofile_started;
extern unsigned long backtrace_depth;
-
+
struct super_block;
struct dentry;
-void oprofile_create_files(struct super_block * sb, struct dentry * root);
-void oprofile_timer_init(struct oprofile_operations * ops);
+void oprofile_create_files(struct super_block *sb, struct dentry *root);
+void oprofile_timer_init(struct oprofile_operations *ops);
int oprofile_set_backtrace(unsigned long depth);
-
+
#endif /* OPROF_H */
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c
index ef953ba5ab6..cc106d503ac 100644
--- a/drivers/oprofile/oprofile_files.c
+++ b/drivers/oprofile/oprofile_files.c
@@ -13,18 +13,18 @@
#include "event_buffer.h"
#include "oprofile_stats.h"
#include "oprof.h"
-
+
unsigned long fs_buffer_size = 131072;
unsigned long fs_cpu_buffer_size = 8192;
unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
-static ssize_t depth_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
+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);
}
-static ssize_t depth_write(struct file * file, char const __user * buf, size_t count, loff_t * offset)
+static ssize_t depth_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
{
unsigned long val;
int retval;
@@ -49,8 +49,8 @@ static const struct file_operations depth_fops = {
.write = depth_write
};
-
-static ssize_t pointer_size_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
+
+static ssize_t pointer_size_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
return oprofilefs_ulong_to_user(sizeof(void *), buf, count, offset);
}
@@ -61,24 +61,24 @@ static const struct file_operations pointer_size_fops = {
};
-static ssize_t cpu_type_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
+static ssize_t cpu_type_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
return oprofilefs_str_to_user(oprofile_ops.cpu_type, buf, count, offset);
}
-
-
+
+
static const struct file_operations cpu_type_fops = {
.read = cpu_type_read,
};
-
-
-static ssize_t enable_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
+
+
+static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
return oprofilefs_ulong_to_user(oprofile_started, buf, count, offset);
}
-static ssize_t enable_write(struct file * file, char const __user * buf, size_t count, loff_t * offset)
+static ssize_t enable_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
{
unsigned long val;
int retval;
@@ -89,7 +89,7 @@ static ssize_t enable_write(struct file * file, char const __user * buf, size_t
retval = oprofilefs_ulong_from_user(&val, buf, count);
if (retval)
return retval;
-
+
if (val)
retval = oprofile_start();
else
@@ -100,14 +100,14 @@ static ssize_t enable_write(struct file * file, char const __user * buf, size_t
return count;
}
-
+
static const struct file_operations enable_fops = {
.read = enable_read,
.write = enable_write,
};
-static ssize_t dump_write(struct file * file, char const __user * buf, size_t count, loff_t * offset)
+static ssize_t dump_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
{
wake_up_buffer_waiter();
return count;
@@ -117,8 +117,8 @@ static ssize_t dump_write(struct file * file, char const __user * buf, size_t co
static const struct file_operations dump_fops = {
.write = dump_write,
};
-
-void oprofile_create_files(struct super_block * sb, struct dentry * root)
+
+void oprofile_create_files(struct super_block *sb, struct dentry *root)
{
oprofilefs_create_file(sb, root, "enable", &enable_fops);
oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
@@ -126,7 +126,7 @@ void oprofile_create_files(struct super_block * sb, struct dentry * root)
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_file(sb, root, "cpu_type", &cpu_type_fops);
+ 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);
oprofile_create_stats_files(sb, root);
diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c
index f99b28e7b79..e1f6ce03705 100644
--- a/drivers/oprofile/oprofile_stats.c
+++ b/drivers/oprofile/oprofile_stats.c
@@ -11,17 +11,17 @@
#include <linux/smp.h>
#include <linux/cpumask.h>
#include <linux/threads.h>
-
+
#include "oprofile_stats.h"
#include "cpu_buffer.h"
-
+
struct oprofile_stat_struct oprofile_stats;
-
+
void oprofile_reset_stats(void)
{
- struct oprofile_cpu_buffer * cpu_buf;
+ struct oprofile_cpu_buffer *cpu_buf;
int i;
-
+
for_each_possible_cpu(i) {
cpu_buf = &per_cpu(cpu_buffer, i);
cpu_buf->sample_received = 0;
@@ -29,18 +29,18 @@ void oprofile_reset_stats(void)
cpu_buf->backtrace_aborted = 0;
cpu_buf->sample_invalid_eip = 0;
}
-
+
atomic_set(&oprofile_stats.sample_lost_no_mm, 0);
atomic_set(&oprofile_stats.sample_lost_no_mapping, 0);
atomic_set(&oprofile_stats.event_lost_overflow, 0);
}
-void oprofile_create_stats_files(struct super_block * sb, struct dentry * root)
+void oprofile_create_stats_files(struct super_block *sb, struct dentry *root)
{
- struct oprofile_cpu_buffer * cpu_buf;
- struct dentry * cpudir;
- struct dentry * dir;
+ struct oprofile_cpu_buffer *cpu_buf;
+ struct dentry *cpudir;
+ struct dentry *dir;
char buf[10];
int i;
@@ -52,7 +52,7 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root)
cpu_buf = &per_cpu(cpu_buffer, i);
snprintf(buf, 10, "cpu%d", i);
cpudir = oprofilefs_mkdir(sb, dir, buf);
-
+
/* Strictly speaking access to these ulongs is racy,
* but we can't simply lock them, and they are
* informational only.
@@ -66,7 +66,7 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root)
oprofilefs_create_ro_ulong(sb, cpudir, "sample_invalid_eip",
&cpu_buf->sample_invalid_eip);
}
-
+
oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mm",
&oprofile_stats.sample_lost_no_mm);
oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mapping",
diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h
index 6d755a633f1..3da0d08dc1f 100644
--- a/drivers/oprofile/oprofile_stats.h
+++ b/drivers/oprofile/oprofile_stats.h
@@ -11,7 +11,7 @@
#define OPROFILE_STATS_H
#include <asm/atomic.h>
-
+
struct oprofile_stat_struct {
atomic_t sample_lost_no_mm;
atomic_t sample_lost_no_mapping;
@@ -20,14 +20,14 @@ struct oprofile_stat_struct {
};
extern struct oprofile_stat_struct oprofile_stats;
-
+
/* reset all stats to zero */
void oprofile_reset_stats(void);
-
+
struct super_block;
struct dentry;
-
+
/* create the stats/ dir */
-void oprofile_create_stats_files(struct super_block * sb, struct dentry * root);
+void oprofile_create_stats_files(struct super_block *sb, struct dentry *root);
#endif /* OPROFILE_STATS_H */
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index 8543cb26cf3..ddc4c59f02d 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -23,9 +23,9 @@
DEFINE_SPINLOCK(oprofilefs_lock);
-static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode)
+static struct inode *oprofilefs_get_inode(struct super_block *sb, int mode)
{
- struct inode * inode = new_inode(sb);
+ struct inode *inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
@@ -44,7 +44,7 @@ static struct super_operations s_ops = {
};
-ssize_t oprofilefs_str_to_user(char const * str, char __user * buf, size_t count, loff_t * offset)
+ssize_t oprofilefs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset)
{
return simple_read_from_buffer(buf, count, offset, str, strlen(str));
}
@@ -52,7 +52,7 @@ ssize_t oprofilefs_str_to_user(char const * str, char __user * buf, size_t count
#define TMPBUFSIZE 50
-ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t count, loff_t * offset)
+ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
{
char tmpbuf[TMPBUFSIZE];
size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
@@ -62,7 +62,7 @@ ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t co
}
-int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, size_t count)
+int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
{
char tmpbuf[TMPBUFSIZE];
unsigned long flags;
@@ -85,16 +85,16 @@ int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, siz
}
-static ssize_t ulong_read_file(struct file * file, char __user * buf, size_t count, loff_t * offset)
+static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
- unsigned long * val = file->private_data;
+ unsigned long *val = file->private_data;
return oprofilefs_ulong_to_user(*val, buf, count, offset);
}
-static ssize_t ulong_write_file(struct file * file, char const __user * buf, size_t count, loff_t * offset)
+static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
{
- unsigned long * value = file->private_data;
+ unsigned long *value = file->private_data;
int retval;
if (*offset)
@@ -108,7 +108,7 @@ static ssize_t ulong_write_file(struct file * file, char const __user * buf, siz
}
-static int default_open(struct inode * inode, struct file * filp)
+static int default_open(struct inode *inode, struct file *filp)
{
if (inode->i_private)
filp->private_data = inode->i_private;
@@ -129,12 +129,12 @@ static const struct file_operations ulong_ro_fops = {
};
-static struct dentry * __oprofilefs_create_file(struct super_block * sb,
- struct dentry * root, char const * name, const struct file_operations * fops,
+static struct dentry *__oprofilefs_create_file(struct super_block *sb,
+ struct dentry *root, char const *name, const struct file_operations *fops,
int perm)
{
- struct dentry * dentry;
- struct inode * inode;
+ struct dentry *dentry;
+ struct inode *inode;
dentry = d_alloc_name(root, name);
if (!dentry)
@@ -150,10 +150,10 @@ static struct dentry * __oprofilefs_create_file(struct super_block * sb,
}
-int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
- char const * name, unsigned long * val)
+int oprofilefs_create_ulong(struct super_block *sb, struct dentry *root,
+ char const *name, unsigned long *val)
{
- struct dentry * d = __oprofilefs_create_file(sb, root, name,
+ struct dentry *d = __oprofilefs_create_file(sb, root, name,
&ulong_fops, 0644);
if (!d)
return -EFAULT;
@@ -163,10 +163,10 @@ int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
}
-int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
- char const * name, unsigned long * val)
+int oprofilefs_create_ro_ulong(struct super_block *sb, struct dentry *root,
+ char const *name, unsigned long *val)
{
- struct dentry * d = __oprofilefs_create_file(sb, root, name,
+ struct dentry *d = __oprofilefs_create_file(sb, root, name,
&ulong_ro_fops, 0444);
if (!d)
return -EFAULT;
@@ -176,23 +176,23 @@ int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
}
-static ssize_t atomic_read_file(struct file * file, char __user * buf, size_t count, loff_t * offset)
+static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
- atomic_t * val = file->private_data;
+ atomic_t *val = file->private_data;
return oprofilefs_ulong_to_user(atomic_read(val), buf, count, offset);
}
-
+
static const struct file_operations atomic_ro_fops = {
.read = atomic_read_file,
.open = default_open,
};
-
-int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
- char const * name, atomic_t * val)
+
+int oprofilefs_create_ro_atomic(struct super_block *sb, struct dentry *root,
+ char const *name, atomic_t *val)
{
- struct dentry * d = __oprofilefs_create_file(sb, root, name,
+ struct dentry *d = __oprofilefs_create_file(sb, root, name,
&atomic_ro_fops, 0444);
if (!d)
return -EFAULT;
@@ -201,9 +201,9 @@ int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
return 0;
}
-
-int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
- char const * name, const struct file_operations * fops)
+
+int oprofilefs_create_file(struct super_block *sb, struct dentry *root,
+ char const *name, const struct file_operations *fops)
{
if (!__oprofilefs_create_file(sb, root, name, fops, 0644))
return -EFAULT;
@@ -211,8 +211,8 @@ int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
}
-int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root,
- char const * name, const struct file_operations * fops, int perm)
+int oprofilefs_create_file_perm(struct super_block *sb, struct dentry *root,
+ char const *name, const struct file_operations *fops, int perm)
{
if (!__oprofilefs_create_file(sb, root, name, fops, perm))
return -EFAULT;
@@ -220,11 +220,11 @@ int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root,
}
-struct dentry * oprofilefs_mkdir(struct super_block * sb,
- struct dentry * root, char const * name)
+struct dentry *oprofilefs_mkdir(struct super_block *sb,
+ struct dentry *root, char const *name)
{
- struct dentry * dentry;
- struct inode * inode;
+ struct dentry *dentry;
+ struct inode *inode;
dentry = d_alloc_name(root, name);
if (!dentry)
@@ -241,10 +241,10 @@ struct dentry * oprofilefs_mkdir(struct super_block * sb,
}
-static int oprofilefs_fill_super(struct super_block * sb, void * data, int silent)
+static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent)
{
- struct inode * root_inode;
- struct dentry * root_dentry;
+ struct inode *root_inode;
+ struct dentry *root_dentry;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c
index 710a45f0d73..333f915568c 100644
--- a/drivers/oprofile/timer_int.c
+++ b/drivers/oprofile/timer_int.c
@@ -19,7 +19,7 @@
static int timer_notify(struct pt_regs *regs)
{
- oprofile_add_sample(regs, 0);
+ oprofile_add_sample(regs, 0);
return 0;
}
@@ -35,7 +35,7 @@ static void timer_stop(void)
}
-void __init oprofile_timer_init(struct oprofile_operations * ops)
+void __init oprofile_timer_init(struct oprofile_operations *ops)
{
ops->create_files = NULL;
ops->setup = NULL;
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index b30e38f3a50..dcc1e9958d2 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -66,15 +66,8 @@
#undef DEBUG_CCIO_RUN_SG
#ifdef CONFIG_PROC_FS
-/*
- * CCIO_SEARCH_TIME can help measure how fast the bitmap search is.
- * impacts performance though - ditch it if you don't use it.
- */
-#define CCIO_SEARCH_TIME
-#undef CCIO_MAP_STATS
-#else
-#undef CCIO_SEARCH_TIME
-#undef CCIO_MAP_STATS
+/* depends on proc fs support. But costs CPU performance. */
+#undef CCIO_COLLECT_STATS
#endif
#include <linux/proc_fs.h>
@@ -239,12 +232,10 @@ struct ioc {
u32 res_size; /* size of resource map in bytes */
spinlock_t res_lock;
-#ifdef CCIO_SEARCH_TIME
+#ifdef CCIO_COLLECT_STATS
#define CCIO_SEARCH_SAMPLE 0x100
unsigned long avg_search[CCIO_SEARCH_SAMPLE];
unsigned long avg_idx; /* current index into avg_search */
-#endif
-#ifdef CCIO_MAP_STATS
unsigned long used_pages;
unsigned long msingle_calls;
unsigned long msingle_pages;
@@ -351,7 +342,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
unsigned int pages_needed = size >> IOVP_SHIFT;
unsigned int res_idx;
unsigned long boundary_size;
-#ifdef CCIO_SEARCH_TIME
+#ifdef CCIO_COLLECT_STATS
unsigned long cr_start = mfctl(16);
#endif
@@ -406,7 +397,7 @@ resource_found:
DBG_RES("%s() res_idx %d res_hint: %d\n",
__func__, res_idx, ioc->res_hint);
-#ifdef CCIO_SEARCH_TIME
+#ifdef CCIO_COLLECT_STATS
{
unsigned long cr_end = mfctl(16);
unsigned long tmp = cr_end - cr_start;
@@ -416,7 +407,7 @@ resource_found:
ioc->avg_search[ioc->avg_idx++] = cr_start;
ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1;
#endif
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
ioc->used_pages += pages_needed;
#endif
/*
@@ -452,7 +443,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
DBG_RES("%s(): res_idx: %d pages_mapped %d\n",
__func__, res_idx, pages_mapped);
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
ioc->used_pages -= pages_mapped;
#endif
@@ -764,7 +755,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
size = ALIGN(size + offset, IOVP_SIZE);
spin_lock_irqsave(&ioc->res_lock, flags);
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
ioc->msingle_calls++;
ioc->msingle_pages += size >> IOVP_SHIFT;
#endif
@@ -828,7 +819,7 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
spin_lock_irqsave(&ioc->res_lock, flags);
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
ioc->usingle_calls++;
ioc->usingle_pages += size >> IOVP_SHIFT;
#endif
@@ -894,7 +885,7 @@ ccio_free_consistent(struct device *dev, size_t size, void *cpu_addr,
*/
#define PIDE_FLAG 0x80000000UL
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
#define IOMMU_MAP_STATS
#endif
#include "iommu-helpers.h"
@@ -938,7 +929,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
spin_lock_irqsave(&ioc->res_lock, flags);
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
ioc->msg_calls++;
#endif
@@ -997,13 +988,13 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
DBG_RUN_SG("%s() START %d entries, %08lx,%x\n",
__func__, nents, sg_virt_addr(sglist), sglist->length);
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
ioc->usg_calls++;
#endif
while(sg_dma_len(sglist) && nents--) {
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
#endif
ccio_unmap_single(dev, sg_dma_address(sglist),
@@ -1048,7 +1039,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
len += seq_printf(m, "IO PDIR size : %d bytes (%d entries)\n",
total_pages * 8, total_pages);
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
len += seq_printf(m, "IO PDIR entries : %ld free %ld used (%d%%)\n",
total_pages - ioc->used_pages, ioc->used_pages,
(int)(ioc->used_pages * 100 / total_pages));
@@ -1057,7 +1048,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
len += seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n",
ioc->res_size, total_pages);
-#ifdef CCIO_SEARCH_TIME
+#ifdef CCIO_COLLECT_STATS
min = max = ioc->avg_search[0];
for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) {
avg += ioc->avg_search[j];
@@ -1070,7 +1061,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
len += seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
min, avg, max);
#endif
-#ifdef CCIO_MAP_STATS
+#ifdef CCIO_COLLECT_STATS
len += seq_printf(m, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n",
ioc->msingle_calls, ioc->msingle_pages,
(int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
@@ -1088,7 +1079,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
len += seq_printf(m, "pci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n\n\n",
ioc->usg_calls, ioc->usg_pages,
(int)((ioc->usg_pages * 1000)/ioc->usg_calls));
-#endif /* CCIO_MAP_STATS */
+#endif /* CCIO_COLLECT_STATS */
ioc = ioc->next;
}
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index fd56128525d..3bc54b30c3a 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -298,7 +298,8 @@ struct pci_port_ops dino_port_ops = {
static void dino_disable_irq(unsigned int irq)
{
- struct dino_device *dino_dev = irq_desc[irq].chip_data;
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct dino_device *dino_dev = desc->chip_data;
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq);
@@ -310,7 +311,8 @@ static void dino_disable_irq(unsigned int irq)
static void dino_enable_irq(unsigned int irq)
{
- struct dino_device *dino_dev = irq_desc[irq].chip_data;
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct dino_device *dino_dev = desc->chip_data;
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
u32 tmp;
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index 771cef59254..7891db50c48 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -346,10 +346,10 @@ static int __init eisa_probe(struct parisc_device *dev)
}
/* Reserve IRQ2 */
- irq_desc[2].action = &irq2_action;
+ irq_to_desc(2)->action = &irq2_action;
for (i = 0; i < 16; i++) {
- irq_desc[i].chip = &eisa_interrupt_type;
+ irq_to_desc(i)->chip = &eisa_interrupt_type;
}
EISA_bus = 1;
diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c
index 5ac207932fd..685d94e69d4 100644
--- a/drivers/parisc/eisa_eeprom.c
+++ b/drivers/parisc/eisa_eeprom.c
@@ -86,7 +86,7 @@ static int eisa_eeprom_open(struct inode *inode, struct file *file)
{
cycle_kernel_lock();
- if (file->f_mode & 2)
+ if (file->f_mode & FMODE_WRITE)
return -EINVAL;
return 0;
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index f7d088b897e..e76db9e4d50 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -108,7 +108,8 @@ int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit)
static void gsc_asic_disable_irq(unsigned int irq)
{
- struct gsc_asic *irq_dev = irq_desc[irq].chip_data;
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct gsc_asic *irq_dev = desc->chip_data;
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
@@ -123,7 +124,8 @@ static void gsc_asic_disable_irq(unsigned int irq)
static void gsc_asic_enable_irq(unsigned int irq)
{
- struct gsc_asic *irq_dev = irq_desc[irq].chip_data;
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct gsc_asic *irq_dev = desc->chip_data;
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
@@ -159,12 +161,14 @@ static struct hw_interrupt_type gsc_asic_interrupt_type = {
int gsc_assign_irq(struct hw_interrupt_type *type, void *data)
{
static int irq = GSC_IRQ_BASE;
+ struct irq_desc *desc;
if (irq > GSC_IRQ_MAX)
return NO_IRQ;
- irq_desc[irq].chip = type;
- irq_desc[irq].chip_data = data;
+ desc = irq_to_desc(irq);
+ desc->chip = type;
+ desc->chip_data = data;
return irq++;
}
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 6fb3f7979f2..7beffcab274 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -619,7 +619,9 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
static struct vector_info *iosapic_get_vector(unsigned int irq)
{
- return irq_desc[irq].chip_data;
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ return desc->chip_data;
}
static void iosapic_disable_irq(unsigned int irq)
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 1e8d2d17f04..1e93c837514 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -363,7 +363,9 @@ int superio_fixup_irq(struct pci_dev *pcidev)
#endif
for (i = 0; i < 16; i++) {
- irq_desc[i].chip = &superio_interrupt_type;
+ struct irq_desc *desc = irq_to_desc(i);
+
+ desc->chip = &superio_interrupt_type;
}
/*
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 8a846adf1dc..96f3bdf0ec4 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2791,6 +2791,7 @@ enum parport_pc_pci_cards {
oxsemi_952,
oxsemi_954,
oxsemi_840,
+ oxsemi_pcie_pport,
aks_0100,
mobility_pp,
netmos_9705,
@@ -2868,6 +2869,7 @@ static struct parport_pc_pci {
/* oxsemi_952 */ { 1, { { 0, 1 }, } },
/* oxsemi_954 */ { 1, { { 0, -1 }, } },
/* oxsemi_840 */ { 1, { { 0, 1 }, } },
+ /* oxsemi_pcie_pport */ { 1, { { 0, 1 }, } },
/* aks_0100 */ { 1, { { 0, -1 }, } },
/* mobility_pp */ { 1, { { 0, 1 }, } },
/* netmos_9705 */ { 1, { { 0, -1 }, } }, /* untested */
@@ -2928,7 +2930,6 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
{ 0x1409, 0x7268, 0x1409, 0x0103, 0, 0, timedia_4008a },
{ 0x1409, 0x7268, 0x1409, 0x0104, 0, 0, timedia_4018 },
{ 0x1409, 0x7268, 0x1409, 0x9018, 0, 0, timedia_9018a },
- { 0x14f2, 0x0121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, mobility_pp },
{ PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_2P_EPP,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_2p_epp },
{ PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_1P_ECP,
@@ -2946,8 +2947,25 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_954 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_12PCI840,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_840 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe840,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe840_G,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_0,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_0_G,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1_G,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1_U,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport },
{ PCI_VENDOR_ID_AKS, PCI_DEVICE_ID_AKS_ALADDINCARD,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, aks_0100 },
+ { 0x14f2, 0x0121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, mobility_pp },
/* NetMos communication controllers */
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9705,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9705 },
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 529d9d7727b..999cc4088b5 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -151,6 +151,13 @@ void pci_bus_add_devices(struct pci_bus *bus)
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");
}
}
}
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index e842e756308..691b3adeb87 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -188,12 +188,11 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
return 0;
}
-static int __init
-dmar_parse_dev(struct dmar_drhd_unit *dmaru)
+static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
{
struct acpi_dmar_hardware_unit *drhd;
static int include_all;
- int ret;
+ int ret = 0;
drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr;
@@ -212,7 +211,7 @@ dmar_parse_dev(struct dmar_drhd_unit *dmaru)
include_all = 1;
}
- if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) {
+ if (ret) {
list_del(&dmaru->list);
kfree(dmaru);
}
@@ -277,18 +276,37 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
drhd = (struct acpi_dmar_hardware_unit *)header;
printk (KERN_INFO PREFIX
"DRHD (flags: 0x%08x)base: 0x%016Lx\n",
- drhd->flags, drhd->address);
+ drhd->flags, (unsigned long long)drhd->address);
break;
case ACPI_DMAR_TYPE_RESERVED_MEMORY:
rmrr = (struct acpi_dmar_reserved_memory *)header;
printk (KERN_INFO PREFIX
"RMRR base: 0x%016Lx end: 0x%016Lx\n",
- rmrr->base_address, rmrr->end_address);
+ (unsigned long long)rmrr->base_address,
+ (unsigned long long)rmrr->end_address);
break;
}
}
+/**
+ * dmar_table_detect - checks to see if the platform supports DMAR devices
+ */
+static int __init dmar_table_detect(void)
+{
+ acpi_status status = AE_OK;
+
+ /* if we could find DMAR table, then there are DMAR devices */
+ status = acpi_get_table(ACPI_SIG_DMAR, 0,
+ (struct acpi_table_header **)&dmar_tbl);
+
+ if (ACPI_SUCCESS(status) && !dmar_tbl) {
+ printk (KERN_WARNING PREFIX "Unable to map DMAR\n");
+ status = AE_NOT_FOUND;
+ }
+
+ return (ACPI_SUCCESS(status) ? 1 : 0);
+}
/**
* parse_dmar_table - parses the DMA reporting table
@@ -300,11 +318,17 @@ parse_dmar_table(void)
struct acpi_dmar_header *entry_header;
int ret = 0;
+ /*
+ * Do it again, earlier dmar_tbl mapping could be mapped with
+ * fixed map.
+ */
+ dmar_table_detect();
+
dmar = (struct acpi_table_dmar *)dmar_tbl;
if (!dmar)
return -ENODEV;
- if (dmar->width < PAGE_SHIFT_4K - 1) {
+ if (dmar->width < PAGE_SHIFT - 1) {
printk(KERN_WARNING PREFIX "Invalid DMAR haw\n");
return -EINVAL;
}
@@ -373,10 +397,10 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
int __init dmar_dev_scope_init(void)
{
- struct dmar_drhd_unit *drhd;
+ struct dmar_drhd_unit *drhd, *drhd_n;
int ret = -ENODEV;
- for_each_drhd_unit(drhd) {
+ list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) {
ret = dmar_parse_dev(drhd);
if (ret)
return ret;
@@ -384,8 +408,8 @@ int __init dmar_dev_scope_init(void)
#ifdef CONFIG_DMAR
{
- struct dmar_rmrr_unit *rmrr;
- for_each_rmrr_units(rmrr) {
+ struct dmar_rmrr_unit *rmrr, *rmrr_n;
+ list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
ret = rmrr_parse_dev(rmrr);
if (ret)
return ret;
@@ -430,33 +454,14 @@ int __init dmar_table_init(void)
return 0;
}
-/**
- * early_dmar_detect - checks to see if the platform supports DMAR devices
- */
-int __init early_dmar_detect(void)
-{
- acpi_status status = AE_OK;
-
- /* if we could find DMAR table, then there are DMAR devices */
- status = acpi_get_table(ACPI_SIG_DMAR, 0,
- (struct acpi_table_header **)&dmar_tbl);
-
- if (ACPI_SUCCESS(status) && !dmar_tbl) {
- printk (KERN_WARNING PREFIX "Unable to map DMAR\n");
- status = AE_NOT_FOUND;
- }
-
- return (ACPI_SUCCESS(status) ? 1 : 0);
-}
-
void __init detect_intel_iommu(void)
{
int ret;
- ret = early_dmar_detect();
+ ret = dmar_table_detect();
-#ifdef CONFIG_DMAR
{
+#ifdef CONFIG_INTR_REMAP
struct acpi_table_dmar *dmar;
/*
* for now we will disable dma-remapping when interrupt
@@ -465,28 +470,18 @@ void __init detect_intel_iommu(void)
* is added, we will not need this any more.
*/
dmar = (struct acpi_table_dmar *) dmar_tbl;
- if (ret && cpu_has_x2apic && dmar->flags & 0x1) {
+ if (ret && cpu_has_x2apic && dmar->flags & 0x1)
printk(KERN_INFO
"Queued invalidation will be enabled to support "
"x2apic and Intr-remapping.\n");
- printk(KERN_INFO
- "Disabling IOMMU detection, because of missing "
- "queued invalidation support for IOTLB "
- "invalidation\n");
- printk(KERN_INFO
- "Use \"nox2apic\", if you want to use Intel "
- " IOMMU for DMA-remapping and don't care about "
- " x2apic support\n");
-
- dmar_disabled = 1;
- return;
- }
-
+#endif
+#ifdef CONFIG_DMAR
if (ret && !no_iommu && !iommu_detected && !swiotlb &&
!dmar_disabled)
iommu_detected = 1;
- }
#endif
+ }
+ dmar_tbl = NULL;
}
@@ -503,7 +498,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
iommu->seq_id = iommu_allocated++;
- iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K);
+ iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE);
if (!iommu->reg) {
printk(KERN_ERR "IOMMU: can't map the region\n");
goto error;
@@ -514,8 +509,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
/* the registers might be more than one page */
map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
cap_max_fault_reg_offset(iommu->cap));
- map_size = PAGE_ALIGN_4K(map_size);
- if (map_size > PAGE_SIZE_4K) {
+ map_size = VTD_PAGE_ALIGN(map_size);
+ if (map_size > VTD_PAGE_SIZE) {
iounmap(iommu->reg);
iommu->reg = ioremap(drhd->reg_base_addr, map_size);
if (!iommu->reg) {
@@ -526,8 +521,10 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
ver = readl(iommu->reg + DMAR_VER_REG);
pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
- drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
- iommu->cap, iommu->ecap);
+ (unsigned long long)drhd->reg_base_addr,
+ DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
+ (unsigned long long)iommu->cap,
+ (unsigned long long)iommu->ecap);
spin_lock_init(&iommu->register_lock);
@@ -580,11 +577,11 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
hw = qi->desc;
- spin_lock(&qi->q_lock);
+ spin_lock_irqsave(&qi->q_lock, flags);
while (qi->free_cnt < 3) {
- spin_unlock(&qi->q_lock);
+ spin_unlock_irqrestore(&qi->q_lock, flags);
cpu_relax();
- spin_lock(&qi->q_lock);
+ spin_lock_irqsave(&qi->q_lock, flags);
}
index = qi->free_head;
@@ -605,15 +602,22 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
qi->free_head = (qi->free_head + 2) % QI_LENGTH;
qi->free_cnt -= 2;
- spin_lock_irqsave(&iommu->register_lock, flags);
+ spin_lock(&iommu->register_lock);
/*
* update the HW tail register indicating the presence of
* new descriptors.
*/
writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG);
- spin_unlock_irqrestore(&iommu->register_lock, flags);
+ spin_unlock(&iommu->register_lock);
while (qi->desc_status[wait_index] != QI_DONE) {
+ /*
+ * We will leave the interrupts disabled, to prevent interrupt
+ * context to queue another cmd while a cmd is already submitted
+ * and waiting for completion on this cpu. This is to avoid
+ * a deadlock where the interrupt context can wait indefinitely
+ * for free slots in the queue.
+ */
spin_unlock(&qi->q_lock);
cpu_relax();
spin_lock(&qi->q_lock);
@@ -622,7 +626,7 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
qi->desc_status[index] = QI_DONE;
reclaim_free_desc(qi);
- spin_unlock(&qi->q_lock);
+ spin_unlock_irqrestore(&qi->q_lock, flags);
}
/*
@@ -638,6 +642,62 @@ void qi_global_iec(struct intel_iommu *iommu)
qi_submit_sync(&desc, iommu);
}
+int qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm,
+ u64 type, int non_present_entry_flush)
+{
+
+ struct qi_desc desc;
+
+ if (non_present_entry_flush) {
+ if (!cap_caching_mode(iommu->cap))
+ return 1;
+ else
+ did = 0;
+ }
+
+ desc.low = QI_CC_FM(fm) | QI_CC_SID(sid) | QI_CC_DID(did)
+ | QI_CC_GRAN(type) | QI_CC_TYPE;
+ desc.high = 0;
+
+ qi_submit_sync(&desc, iommu);
+
+ return 0;
+
+}
+
+int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
+ unsigned int size_order, u64 type,
+ int non_present_entry_flush)
+{
+ u8 dw = 0, dr = 0;
+
+ struct qi_desc desc;
+ int ih = 0;
+
+ if (non_present_entry_flush) {
+ if (!cap_caching_mode(iommu->cap))
+ return 1;
+ else
+ did = 0;
+ }
+
+ if (cap_write_drain(iommu->cap))
+ dw = 1;
+
+ if (cap_read_drain(iommu->cap))
+ dr = 1;
+
+ desc.low = QI_IOTLB_DID(did) | QI_IOTLB_DR(dr) | QI_IOTLB_DW(dw)
+ | QI_IOTLB_GRAN(type) | QI_IOTLB_TYPE;
+ desc.high = QI_IOTLB_ADDR(addr) | QI_IOTLB_IH(ih)
+ | QI_IOTLB_AM(size_order);
+
+ qi_submit_sync(&desc, iommu);
+
+ return 0;
+
+}
+
/*
* Enable Queued Invalidation interface. This is a must to support
* interrupt-remapping. Also used by DMA-remapping, which replaces
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 5a58b075dd8..f9e244da30a 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -50,9 +50,6 @@
#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
-/* name size which is used for entries in pcihpfs */
-#define SLOT_NAME_SIZE 20 /* {_SUN} */
-
struct acpiphp_bridge;
struct acpiphp_slot;
@@ -63,9 +60,13 @@ struct slot {
struct hotplug_slot *hotplug_slot;
struct acpiphp_slot *acpi_slot;
struct hotplug_slot_info info;
- char name[SLOT_NAME_SIZE];
};
+static inline const char *slot_name(struct slot *slot)
+{
+ return hotplug_slot_name(slot->hotplug_slot);
+}
+
/*
* struct acpiphp_bridge - PCI bridge information
*
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 0e496e866a8..95b536a23d2 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -44,6 +44,9 @@
#define MY_NAME "acpiphp"
+/* name size which is used for entries in pcihpfs */
+#define SLOT_NAME_SIZE 21 /* {_SUN} */
+
static int debug;
int acpiphp_debug;
@@ -84,7 +87,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
.get_adapter_status = get_adapter_status,
};
-
/**
* acpiphp_register_attention - set attention LED callback
* @info: must be completely filled with LED callbacks
@@ -136,7 +138,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
/* enable the specified slot */
return acpiphp_enable_slot(slot->acpi_slot);
@@ -154,7 +156,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
struct slot *slot = hotplug_slot->private;
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
/* disable the specified slot */
retval = acpiphp_disable_slot(slot->acpi_slot);
@@ -177,7 +179,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
{
int retval = -ENODEV;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
if (attention_info && try_module_get(attention_info->owner)) {
retval = attention_info->set_attn(hotplug_slot, status);
@@ -200,7 +202,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
*value = acpiphp_get_power_status(slot->acpi_slot);
@@ -222,7 +224,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
int retval = -EINVAL;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
if (attention_info && try_module_get(attention_info->owner)) {
retval = attention_info->get_attn(hotplug_slot, value);
@@ -245,7 +247,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
*value = acpiphp_get_latch_status(slot->acpi_slot);
@@ -265,7 +267,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
*value = acpiphp_get_adapter_status(slot->acpi_slot);
@@ -299,7 +301,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
kfree(slot->hotplug_slot);
kfree(slot);
@@ -310,6 +312,7 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
{
struct slot *slot;
int retval = -ENOMEM;
+ char name[SLOT_NAME_SIZE];
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot)
@@ -321,8 +324,6 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
slot->hotplug_slot->info = &slot->info;
- slot->hotplug_slot->name = slot->name;
-
slot->hotplug_slot->private = slot;
slot->hotplug_slot->release = &release_slot;
slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
@@ -336,11 +337,12 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
acpiphp_slot->slot = slot;
- snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun);
+ snprintf(name, SLOT_NAME_SIZE, "%u", slot->acpi_slot->sun);
retval = pci_hp_register(slot->hotplug_slot,
acpiphp_slot->bridge->pci_bus,
- acpiphp_slot->device);
+ acpiphp_slot->device,
+ name);
if (retval == -EBUSY)
goto error_hpslot;
if (retval) {
@@ -348,7 +350,7 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
goto error_hpslot;
}
- info("Slot [%s] registered\n", slot->hotplug_slot->name);
+ info("Slot [%s] registered\n", slot_name(slot));
return 0;
error_hpslot:
@@ -365,7 +367,7 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
struct slot *slot = acpiphp_slot->slot;
int retval = 0;
- info ("Slot [%s] unregistered\n", slot->hotplug_slot->name);
+ info("Slot [%s] unregistered\n", slot_name(slot));
retval = pci_hp_deregister(slot->hotplug_slot);
if (retval)
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index a3e4705dd8f..955aae4071f 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -169,7 +169,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
}
-
+static struct acpi_dock_ops acpiphp_dock_ops = {
+ .handler = handle_hotplug_event_func,
+};
/* callback routine to register each ACPI PCI slot object */
static acpi_status
@@ -180,7 +182,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
struct acpiphp_func *newfunc;
acpi_handle tmp;
acpi_status status = AE_OK;
- unsigned long adr, sun;
+ unsigned long long adr, sun;
int device, function, retval;
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
@@ -285,7 +287,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
*/
newfunc->flags &= ~FUNC_HAS_EJ0;
if (register_hotplug_dock_device(handle,
- handle_hotplug_event_func, newfunc))
+ &acpiphp_dock_ops, newfunc))
dbg("failed to register dock device\n");
/* we need to be notified when dock events happen
@@ -528,7 +530,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
acpi_handle dummy_handle;
- unsigned long tmp;
+ unsigned long long tmp;
int device, function;
struct pci_dev *dev;
struct pci_bus *pci_bus = context;
@@ -573,7 +575,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
static int add_bridge(acpi_handle handle)
{
acpi_status status;
- unsigned long tmp;
+ unsigned long long tmp;
int seg, bus;
acpi_handle dummy_handle;
struct pci_bus *pci_bus;
@@ -767,7 +769,7 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
{
acpi_status status;
int result = -1;
- unsigned long gsb;
+ unsigned long long gsb;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *obj;
void *table;
@@ -808,7 +810,7 @@ static acpi_status
ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
- unsigned long sta;
+ unsigned long long sta;
acpi_handle tmp;
struct pci_dev *pdev;
u32 gsi_base;
@@ -872,7 +874,7 @@ static acpi_status
ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
- unsigned long sta;
+ unsigned long long sta;
acpi_handle tmp;
u32 gsi_base;
struct acpiphp_ioapic *pos, *n, *ioapic = NULL;
@@ -1264,7 +1266,7 @@ static int disable_device(struct acpiphp_slot *slot)
static unsigned int get_slot_status(struct acpiphp_slot *slot)
{
acpi_status status;
- unsigned long sta = 0;
+ unsigned long long sta = 0;
u32 dvid;
struct list_head *l;
struct acpiphp_func *func;
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 2b7c45e3937..b291ee68b4f 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -183,7 +183,7 @@ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status)
union acpi_object args[2];
struct acpi_object_list params = { .pointer = args, .count = 2 };
acpi_status stat;
- unsigned long rc;
+ unsigned long long rc;
union apci_descriptor *ibm_slot;
ibm_slot = ibm_slot_from_id(hpslot_to_sun(slot));
diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
index d9769b30be9..9fff878cf02 100644
--- a/drivers/pci/hotplug/cpci_hotplug.h
+++ b/drivers/pci/hotplug/cpci_hotplug.h
@@ -30,6 +30,7 @@
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
/* PICMG 2.1 R2.0 HS CSR bits: */
#define HS_CSR_INS 0x0080
@@ -69,6 +70,11 @@ struct cpci_hp_controller {
struct cpci_hp_controller_ops *ops;
};
+static inline const char *slot_name(struct slot *slot)
+{
+ return hotplug_slot_name(slot->hotplug_slot);
+}
+
extern int cpci_hp_register_controller(struct cpci_hp_controller *controller);
extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller);
extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last);
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index 935947991dc..de94f4feef8 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -108,7 +108,7 @@ enable_slot(struct hotplug_slot *hotplug_slot)
struct slot *slot = hotplug_slot->private;
int retval = 0;
- dbg("%s - physical_slot = %s", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s", __func__, slot_name(slot));
if (controller->ops->set_power)
retval = controller->ops->set_power(slot, 1);
@@ -121,25 +121,23 @@ disable_slot(struct hotplug_slot *hotplug_slot)
struct slot *slot = hotplug_slot->private;
int retval = 0;
- dbg("%s - physical_slot = %s", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s", __func__, slot_name(slot));
down_write(&list_rwsem);
/* Unconfigure device */
- dbg("%s - unconfiguring slot %s",
- __func__, slot->hotplug_slot->name);
+ dbg("%s - unconfiguring slot %s", __func__, slot_name(slot));
if ((retval = cpci_unconfigure_slot(slot))) {
err("%s - could not unconfigure slot %s",
- __func__, slot->hotplug_slot->name);
+ __func__, slot_name(slot));
goto disable_error;
}
- dbg("%s - finished unconfiguring slot %s",
- __func__, slot->hotplug_slot->name);
+ dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot));
/* Clear EXT (by setting it) */
if (cpci_clear_ext(slot)) {
err("%s - could not clear EXT for slot %s",
- __func__, slot->hotplug_slot->name);
+ __func__, slot_name(slot));
retval = -ENODEV;
goto disable_error;
}
@@ -214,7 +212,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
struct slot *slot = hotplug_slot->private;
kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
if (slot->dev)
pci_dev_put(slot->dev);
@@ -222,12 +219,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
}
#define SLOT_NAME_SIZE 6
-static void
-make_slot_name(struct slot *slot)
-{
- snprintf(slot->hotplug_slot->name,
- SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number);
-}
int
cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
@@ -235,7 +226,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
struct slot *slot;
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *info;
- char *name;
+ char name[SLOT_NAME_SIZE];
int status = -ENOMEM;
int i;
@@ -262,34 +253,31 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
goto error_hpslot;
hotplug_slot->info = info;
- name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
- if (!name)
- goto error_info;
- hotplug_slot->name = name;
-
slot->bus = bus;
slot->number = i;
slot->devfn = PCI_DEVFN(i, 0);
+ snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i);
+
hotplug_slot->private = slot;
hotplug_slot->release = &release_slot;
- make_slot_name(slot);
hotplug_slot->ops = &cpci_hotplug_slot_ops;
/*
* Initialize the slot info structure with some known
* good values.
*/
- dbg("initializing slot %s", slot->hotplug_slot->name);
+ dbg("initializing slot %s", name);
info->power_status = cpci_get_power_status(slot);
info->attention_status = cpci_get_attention_status(slot);
- dbg("registering slot %s", slot->hotplug_slot->name);
- status = pci_hp_register(slot->hotplug_slot, bus, i);
+ dbg("registering slot %s", name);
+ status = pci_hp_register(slot->hotplug_slot, bus, i, name);
if (status) {
err("pci_hp_register failed with error %d", status);
- goto error_name;
+ goto error_info;
}
+ dbg("slot registered with name: %s", slot_name(slot));
/* Add slot to our internal list */
down_write(&list_rwsem);
@@ -298,8 +286,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
up_write(&list_rwsem);
}
return 0;
-error_name:
- kfree(name);
error_info:
kfree(info);
error_hpslot:
@@ -327,7 +313,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
list_del(&slot->slot_list);
slots--;
- dbg("deregistering slot %s", slot->hotplug_slot->name);
+ dbg("deregistering slot %s", slot_name(slot));
status = pci_hp_deregister(slot->hotplug_slot);
if (status) {
err("pci_hp_deregister failed with error %d",
@@ -379,11 +365,10 @@ init_slots(int clear_ins)
return -1;
}
list_for_each_entry(slot, &slot_list, slot_list) {
- dbg("%s - looking at slot %s",
- __func__, slot->hotplug_slot->name);
+ dbg("%s - looking at slot %s", __func__, slot_name(slot));
if (clear_ins && cpci_check_and_clear_ins(slot))
dbg("%s - cleared INS for slot %s",
- __func__, slot->hotplug_slot->name);
+ __func__, slot_name(slot));
dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
if (dev) {
if (update_adapter_status(slot->hotplug_slot, 1))
@@ -414,8 +399,7 @@ check_slots(void)
}
extracted = inserted = 0;
list_for_each_entry(slot, &slot_list, slot_list) {
- dbg("%s - looking at slot %s",
- __func__, slot->hotplug_slot->name);
+ dbg("%s - looking at slot %s", __func__, slot_name(slot));
if (cpci_check_and_clear_ins(slot)) {
/*
* Some broken hardware (e.g. PLX 9054AB) asserts
@@ -423,35 +407,34 @@ check_slots(void)
*/
if (slot->dev) {
warn("slot %s already inserted",
- slot->hotplug_slot->name);
+ slot_name(slot));
inserted++;
continue;
}
/* Process insertion */
- dbg("%s - slot %s inserted",
- __func__, slot->hotplug_slot->name);
+ dbg("%s - slot %s inserted", __func__, slot_name(slot));
/* GSM, debug */
hs_csr = cpci_get_hs_csr(slot);
dbg("%s - slot %s HS_CSR (1) = %04x",
- __func__, slot->hotplug_slot->name, hs_csr);
+ __func__, slot_name(slot), hs_csr);
/* Configure device */
dbg("%s - configuring slot %s",
- __func__, slot->hotplug_slot->name);
+ __func__, slot_name(slot));
if (cpci_configure_slot(slot)) {
err("%s - could not configure slot %s",
- __func__, slot->hotplug_slot->name);
+ __func__, slot_name(slot));
continue;
}
dbg("%s - finished configuring slot %s",
- __func__, slot->hotplug_slot->name);
+ __func__, slot_name(slot));
/* GSM, debug */
hs_csr = cpci_get_hs_csr(slot);
dbg("%s - slot %s HS_CSR (2) = %04x",
- __func__, slot->hotplug_slot->name, hs_csr);
+ __func__, slot_name(slot), hs_csr);
if (update_latch_status(slot->hotplug_slot, 1))
warn("failure to update latch file");
@@ -464,18 +447,18 @@ check_slots(void)
/* GSM, debug */
hs_csr = cpci_get_hs_csr(slot);
dbg("%s - slot %s HS_CSR (3) = %04x",
- __func__, slot->hotplug_slot->name, hs_csr);
+ __func__, slot_name(slot), hs_csr);
inserted++;
} else if (cpci_check_ext(slot)) {
/* Process extraction request */
dbg("%s - slot %s extracted",
- __func__, slot->hotplug_slot->name);
+ __func__, slot_name(slot));
/* GSM, debug */
hs_csr = cpci_get_hs_csr(slot);
dbg("%s - slot %s HS_CSR = %04x",
- __func__, slot->hotplug_slot->name, hs_csr);
+ __func__, slot_name(slot), hs_csr);
if (!slot->extracting) {
if (update_latch_status(slot->hotplug_slot, 0)) {
@@ -493,7 +476,7 @@ check_slots(void)
* bother trying to tell the driver or not?
*/
err("card in slot %s was improperly removed",
- slot->hotplug_slot->name);
+ slot_name(slot));
if (update_adapter_status(slot->hotplug_slot, 0))
warn("failure to update adapter file");
slot->extracting = 0;
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index df82b95e287..829c327cfb5 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -209,7 +209,7 @@ int cpci_led_on(struct slot* slot)
hs_cap + 2,
hs_csr)) {
err("Could not set LOO for slot %s",
- slot->hotplug_slot->name);
+ hotplug_slot_name(slot->hotplug_slot));
return -ENODEV;
}
}
@@ -238,7 +238,7 @@ int cpci_led_off(struct slot* slot)
hs_cap + 2,
hs_csr)) {
err("Could not clear LOO for slot %s",
- slot->hotplug_slot->name);
+ hotplug_slot_name(slot->hotplug_slot));
return -ENODEV;
}
}
diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
index b1decfa88b7..afaf8f69f73 100644
--- a/drivers/pci/hotplug/cpqphp.h
+++ b/drivers/pci/hotplug/cpqphp.h
@@ -449,6 +449,11 @@ extern u8 cpqhp_disk_irq;
/* inline functions */
+static inline char *slot_name(struct slot *slot)
+{
+ return hotplug_slot_name(slot->hotplug_slot);
+}
+
/*
* return_resource
*
@@ -696,14 +701,6 @@ static inline int get_presence_status(struct controller *ctrl, struct slot *slot
return presence_save;
}
-#define SLOT_NAME_SIZE 10
-
-static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
-{
- snprintf(buffer, buffer_size, "%d", slot->number);
-}
-
-
static inline int wait_for_ctrl_irq(struct controller *ctrl)
{
DECLARE_WAITQUEUE(wait, current);
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index 54defec51d0..724d42c4adb 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -315,14 +315,15 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
}
+#define SLOT_NAME_SIZE 10
+
static int ctrl_slot_setup(struct controller *ctrl,
void __iomem *smbios_start,
void __iomem *smbios_table)
@@ -335,6 +336,7 @@ static int ctrl_slot_setup(struct controller *ctrl,
u8 slot_number;
u8 ctrl_slot;
u32 tempdword;
+ char name[SLOT_NAME_SIZE];
void __iomem *slot_entry= NULL;
int result = -ENOMEM;
@@ -363,16 +365,12 @@ static int ctrl_slot_setup(struct controller *ctrl,
if (!hotplug_slot->info)
goto error_hpslot;
hotplug_slot_info = hotplug_slot->info;
- hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
-
- if (!hotplug_slot->name)
- goto error_info;
slot->ctrl = ctrl;
slot->bus = ctrl->bus;
slot->device = slot_device;
slot->number = slot_number;
- dbg("slot->number = %d\n", slot->number);
+ dbg("slot->number = %u\n", slot->number);
slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9,
slot_entry);
@@ -418,9 +416,9 @@ static int ctrl_slot_setup(struct controller *ctrl,
/* register this slot with the hotplug pci core */
hotplug_slot->release = &release_slot;
hotplug_slot->private = slot;
- make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
+ snprintf(name, SLOT_NAME_SIZE, "%u", slot->number);
hotplug_slot->ops = &cpqphp_hotplug_slot_ops;
-
+
hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot);
hotplug_slot_info->attention_status =
cpq_get_attention_status(ctrl, slot);
@@ -436,10 +434,11 @@ static int ctrl_slot_setup(struct controller *ctrl,
slot_number);
result = pci_hp_register(hotplug_slot,
ctrl->pci_dev->subordinate,
- slot->device);
+ slot->device,
+ name);
if (result) {
err("pci_hp_register failed with error %d\n", result);
- goto error_name;
+ goto error_info;
}
slot->next = ctrl->slot;
@@ -451,8 +450,6 @@ static int ctrl_slot_setup(struct controller *ctrl,
}
return 0;
-error_name:
- kfree(hotplug_slot->name);
error_info:
kfree(hotplug_slot_info);
error_hpslot:
@@ -638,7 +635,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
u8 device;
u8 function;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1)
return -ENODEV;
@@ -665,7 +662,7 @@ static int process_SI(struct hotplug_slot *hotplug_slot)
u8 device;
u8 function;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1)
return -ENODEV;
@@ -697,7 +694,7 @@ static int process_SS(struct hotplug_slot *hotplug_slot)
u8 device;
u8 function;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1)
return -ENODEV;
@@ -720,7 +717,7 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value)
struct slot *slot = hotplug_slot->private;
struct controller *ctrl = slot->ctrl;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
return cpqhp_hardware_test(ctrl, value);
}
@@ -731,7 +728,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = hotplug_slot->private;
struct controller *ctrl = slot->ctrl;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
*value = get_slot_enabled(ctrl, slot);
return 0;
@@ -742,7 +739,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = hotplug_slot->private;
struct controller *ctrl = slot->ctrl;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
*value = cpq_get_attention_status(ctrl, slot);
return 0;
@@ -753,7 +750,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = hotplug_slot->private;
struct controller *ctrl = slot->ctrl;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
*value = cpq_get_latch_status(ctrl, slot);
@@ -765,7 +762,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = hotplug_slot->private;
struct controller *ctrl = slot->ctrl;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
*value = get_presence_status(ctrl, slot);
@@ -777,7 +774,7 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
struct slot *slot = hotplug_slot->private;
struct controller *ctrl = slot->ctrl;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
*value = ctrl->speed_capability;
@@ -789,7 +786,7 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
struct slot *slot = hotplug_slot->private;
struct controller *ctrl = slot->ctrl;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
*value = ctrl->speed;
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index ef041ca91c2..a60a2529099 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -1139,7 +1139,7 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
for(slot = ctrl->slot; slot; slot = slot->next) {
if (slot->device == (hp_slot + ctrl->slot_device_offset))
continue;
- if (!slot->hotplug_slot && !slot->hotplug_slot->info)
+ if (!slot->hotplug_slot || !slot->hotplug_slot->info)
continue;
if (slot->hotplug_slot->info->adapter_status == 0)
continue;
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index 146ca9cd156..3a2637a0093 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -66,10 +66,10 @@ struct dummy_slot {
struct pci_dev *dev;
struct work_struct remove_work;
unsigned long removed;
- char name[8];
};
static int debug;
+static int dup_slots;
static LIST_HEAD(slot_list);
static struct workqueue_struct *dummyphp_wq;
@@ -96,10 +96,13 @@ static void dummy_release(struct hotplug_slot *slot)
kfree(dslot);
}
+#define SLOT_NAME_SIZE 8
+
static int add_slot(struct pci_dev *dev)
{
struct dummy_slot *dslot;
struct hotplug_slot *slot;
+ char name[SLOT_NAME_SIZE];
int retval = -ENOMEM;
static int count = 1;
@@ -119,19 +122,22 @@ static int add_slot(struct pci_dev *dev)
if (!dslot)
goto error_info;
- slot->name = dslot->name;
- snprintf(slot->name, sizeof(dslot->name), "fake%d", count++);
- dbg("slot->name = %s\n", slot->name);
+ if (dup_slots)
+ snprintf(name, SLOT_NAME_SIZE, "fake");
+ else
+ snprintf(name, SLOT_NAME_SIZE, "fake%d", count++);
+ dbg("slot->name = %s\n", name);
slot->ops = &dummy_hotplug_slot_ops;
slot->release = &dummy_release;
slot->private = dslot;
- retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn));
+ retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn), name);
if (retval) {
err("pci_hp_register failed with error %d\n", retval);
goto error_dslot;
}
+ dbg("slot->name = %s\n", hotplug_slot_name(slot));
dslot->slot = slot;
dslot->dev = pci_dev_get(dev);
list_add (&dslot->node, &slot_list);
@@ -167,10 +173,11 @@ static void remove_slot(struct dummy_slot *dslot)
{
int retval;
- dbg("removing slot %s\n", dslot->slot->name);
+ dbg("removing slot %s\n", hotplug_slot_name(dslot->slot));
retval = pci_hp_deregister(dslot->slot);
if (retval)
- err("Problem unregistering a slot %s\n", dslot->slot->name);
+ err("Problem unregistering a slot %s\n",
+ hotplug_slot_name(dslot->slot));
}
/* called from the single-threaded workqueue handler to remove a slot */
@@ -308,7 +315,7 @@ static int disable_slot(struct hotplug_slot *slot)
return -ENODEV;
dslot = slot->private;
- dbg("%s - physical_slot = %s\n", __func__, slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(slot));
for (func = 7; func >= 0; func--) {
dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func);
@@ -373,4 +380,5 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
-
+module_param(dup_slots, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dup_slots, "Force duplicate slot names for debugging");
diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h
index 612d9630150..a8d391a4957 100644
--- a/drivers/pci/hotplug/ibmphp.h
+++ b/drivers/pci/hotplug/ibmphp.h
@@ -707,17 +707,16 @@ struct slot {
u8 device;
u8 number;
u8 real_physical_slot_num;
- char name[100];
u32 capabilities;
u8 supported_speed;
u8 supported_bus_mode;
+ u8 flag; /* this is for disable slot and polling */
+ u8 ctlr_index;
struct hotplug_slot *hotplug_slot;
struct controller *ctrl;
struct pci_func *func;
u8 irq[4];
- u8 flag; /* this is for disable slot and polling */
int bit_mode; /* 0 = 32, 1 = 64 */
- u8 ctlr_index;
struct bus_info *bus_on;
struct list_head ibm_slot_list;
u8 status;
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
index 7d27631e6e6..c1abac8ab5c 100644
--- a/drivers/pci/hotplug/ibmphp_ebda.c
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
@@ -123,10 +123,8 @@ static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void)
static void __init print_bus_info (void)
{
struct bus_info *ptr;
- struct list_head *ptr1;
- list_for_each (ptr1, &bus_info_head) {
- ptr = list_entry (ptr1, struct bus_info, bus_info_list);
+ list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
debug ("%s - slot_min = %x\n", __func__, ptr->slot_min);
debug ("%s - slot_max = %x\n", __func__, ptr->slot_max);
debug ("%s - slot_count = %x\n", __func__, ptr->slot_count);
@@ -146,10 +144,8 @@ static void __init print_bus_info (void)
static void print_lo_info (void)
{
struct rio_detail *ptr;
- struct list_head *ptr1;
debug ("print_lo_info ----\n");
- list_for_each (ptr1, &rio_lo_head) {
- ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
+ list_for_each_entry(ptr, &rio_lo_head, rio_detail_list) {
debug ("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
debug ("%s - rio_type = %x\n", __func__, ptr->rio_type);
debug ("%s - owner_id = %x\n", __func__, ptr->owner_id);
@@ -163,10 +159,8 @@ static void print_lo_info (void)
static void print_vg_info (void)
{
struct rio_detail *ptr;
- struct list_head *ptr1;
debug ("%s ---\n", __func__);
- list_for_each (ptr1, &rio_vg_head) {
- ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
+ list_for_each_entry(ptr, &rio_vg_head, rio_detail_list) {
debug ("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
debug ("%s - rio_type = %x\n", __func__, ptr->rio_type);
debug ("%s - owner_id = %x\n", __func__, ptr->owner_id);
@@ -180,10 +174,8 @@ static void print_vg_info (void)
static void __init print_ebda_pci_rsrc (void)
{
struct ebda_pci_rsrc *ptr;
- struct list_head *ptr1;
- list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) {
- ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
+ list_for_each_entry(ptr, &ibmphp_ebda_pci_rsrc_head, ebda_pci_rsrc_list) {
debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
__func__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr);
}
@@ -192,10 +184,8 @@ static void __init print_ebda_pci_rsrc (void)
static void __init print_ibm_slot (void)
{
struct slot *ptr;
- struct list_head *ptr1;
- list_for_each (ptr1, &ibmphp_slot_head) {
- ptr = list_entry (ptr1, struct slot, ibm_slot_list);
+ list_for_each_entry(ptr, &ibmphp_slot_head, ibm_slot_list) {
debug ("%s - slot_number: %x\n", __func__, ptr->number);
}
}
@@ -203,10 +193,8 @@ static void __init print_ibm_slot (void)
static void __init print_opt_vg (void)
{
struct opt_rio *ptr;
- struct list_head *ptr1;
debug ("%s ---\n", __func__);
- list_for_each (ptr1, &opt_vg_head) {
- ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
+ list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
debug ("%s - rio_type %x\n", __func__, ptr->rio_type);
debug ("%s - chassis_num: %x\n", __func__, ptr->chassis_num);
debug ("%s - first_slot_num: %x\n", __func__, ptr->first_slot_num);
@@ -217,13 +205,9 @@ static void __init print_opt_vg (void)
static void __init print_ebda_hpc (void)
{
struct controller *hpc_ptr;
- struct list_head *ptr1;
u16 index;
- list_for_each (ptr1, &ebda_hpc_head) {
-
- hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list);
-
+ list_for_each_entry(hpc_ptr, &ebda_hpc_head, ebda_hpc_list) {
for (index = 0; index < hpc_ptr->slot_count; index++) {
debug ("%s - physical slot#: %x\n", __func__, hpc_ptr->slots[index].slot_num);
debug ("%s - pci bus# of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_bus_num);
@@ -460,9 +444,7 @@ static int __init ebda_rio_table (void)
static struct opt_rio *search_opt_vg (u8 chassis_num)
{
struct opt_rio *ptr;
- struct list_head *ptr1;
- list_for_each (ptr1, &opt_vg_head) {
- ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
+ list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
if (ptr->chassis_num == chassis_num)
return ptr;
}
@@ -473,10 +455,8 @@ static int __init combine_wpg_for_chassis (void)
{
struct opt_rio *opt_rio_ptr = NULL;
struct rio_detail *rio_detail_ptr = NULL;
- struct list_head *list_head_ptr = NULL;
- list_for_each (list_head_ptr, &rio_vg_head) {
- rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
+ list_for_each_entry(rio_detail_ptr, &rio_vg_head, rio_detail_list) {
opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num);
if (!opt_rio_ptr) {
opt_rio_ptr = kzalloc(sizeof(struct opt_rio), GFP_KERNEL);
@@ -497,14 +477,12 @@ static int __init combine_wpg_for_chassis (void)
}
/*
- * reorgnizing linked list of expansion box
+ * reorganizing linked list of expansion box
*/
static struct opt_rio_lo *search_opt_lo (u8 chassis_num)
{
struct opt_rio_lo *ptr;
- struct list_head *ptr1;
- list_for_each (ptr1, &opt_lo_head) {
- ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list);
+ list_for_each_entry(ptr, &opt_lo_head, opt_rio_lo_list) {
if (ptr->chassis_num == chassis_num)
return ptr;
}
@@ -515,10 +493,8 @@ static int combine_wpg_for_expansion (void)
{
struct opt_rio_lo *opt_rio_lo_ptr = NULL;
struct rio_detail *rio_detail_ptr = NULL;
- struct list_head *list_head_ptr = NULL;
- list_for_each (list_head_ptr, &rio_lo_head) {
- rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
+ list_for_each_entry(rio_detail_ptr, &rio_lo_head, rio_detail_list) {
opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num);
if (!opt_rio_lo_ptr) {
opt_rio_lo_ptr = kzalloc(sizeof(struct opt_rio_lo), GFP_KERNEL);
@@ -550,20 +526,17 @@ static int first_slot_num (u8 slot_num, u8 first_slot, u8 var)
{
struct opt_rio *opt_vg_ptr = NULL;
struct opt_rio_lo *opt_lo_ptr = NULL;
- struct list_head *ptr = NULL;
int rc = 0;
if (!var) {
- list_for_each (ptr, &opt_vg_head) {
- opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
+ list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) {
rc = -ENODEV;
break;
}
}
} else {
- list_for_each (ptr, &opt_lo_head) {
- opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
+ list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) {
rc = -ENODEV;
break;
@@ -576,10 +549,8 @@ static int first_slot_num (u8 slot_num, u8 first_slot, u8 var)
static struct opt_rio_lo * find_rxe_num (u8 slot_num)
{
struct opt_rio_lo *opt_lo_ptr;
- struct list_head *ptr;
- list_for_each (ptr, &opt_lo_head) {
- opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
+ list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
//check to see if this slot_num belongs to expansion box
if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1)))
return opt_lo_ptr;
@@ -590,10 +561,8 @@ static struct opt_rio_lo * find_rxe_num (u8 slot_num)
static struct opt_rio * find_chassis_num (u8 slot_num)
{
struct opt_rio *opt_vg_ptr;
- struct list_head *ptr;
- list_for_each (ptr, &opt_vg_head) {
- opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
+ list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
//check to see if this slot_num belongs to chassis
if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0)))
return opt_vg_ptr;
@@ -607,11 +576,9 @@ static struct opt_rio * find_chassis_num (u8 slot_num)
static u8 calculate_first_slot (u8 slot_num)
{
u8 first_slot = 1;
- struct list_head * list;
struct slot * slot_cur;
- list_for_each (list, &ibmphp_slot_head) {
- slot_cur = list_entry (list, struct slot, ibm_slot_list);
+ list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) {
if (slot_cur->ctrl) {
if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num))
first_slot = slot_cur->ctrl->ending_slot_num;
@@ -620,11 +587,14 @@ static u8 calculate_first_slot (u8 slot_num)
return first_slot + 1;
}
+
+#define SLOT_NAME_SIZE 30
+
static char *create_file_name (struct slot * slot_cur)
{
struct opt_rio *opt_vg_ptr = NULL;
struct opt_rio_lo *opt_lo_ptr = NULL;
- static char str[30];
+ static char str[SLOT_NAME_SIZE];
int which = 0; /* rxe = 1, chassis = 0 */
u8 number = 1; /* either chassis or rxe # */
u8 first_slot = 1;
@@ -736,7 +706,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
slot = hotplug_slot->private;
kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
slot->ctrl = NULL;
slot->bus_on = NULL;
@@ -767,7 +736,7 @@ static int __init ebda_rsrc_controller (void)
struct bus_info *bus_info_ptr1, *bus_info_ptr2;
int rc;
struct slot *tmp_slot;
- struct list_head *list;
+ char name[SLOT_NAME_SIZE];
addr = hpc_list_ptr->phys_addr;
for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
@@ -931,12 +900,6 @@ static int __init ebda_rsrc_controller (void)
goto error_no_hp_info;
}
- hp_slot_ptr->name = kmalloc(30, GFP_KERNEL);
- if (!hp_slot_ptr->name) {
- rc = -ENOMEM;
- goto error_no_hp_name;
- }
-
tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL);
if (!tmp_slot) {
rc = -ENOMEM;
@@ -997,12 +960,10 @@ static int __init ebda_rsrc_controller (void)
} /* each hpc */
- list_for_each (list, &ibmphp_slot_head) {
- tmp_slot = list_entry (list, struct slot, ibm_slot_list);
-
- snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
+ list_for_each_entry(tmp_slot, &ibmphp_slot_head, ibm_slot_list) {
+ snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot));
pci_hp_register(tmp_slot->hotplug_slot,
- pci_find_bus(0, tmp_slot->bus), tmp_slot->device);
+ pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name);
}
print_ebda_hpc ();
@@ -1012,8 +973,6 @@ static int __init ebda_rsrc_controller (void)
error:
kfree (hp_slot_ptr->private);
error_no_slot:
- kfree (hp_slot_ptr->name);
-error_no_hp_name:
kfree (hp_slot_ptr->info);
error_no_hp_info:
kfree (hp_slot_ptr);
@@ -1101,10 +1060,8 @@ u16 ibmphp_get_total_controllers (void)
struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num)
{
struct slot *slot;
- struct list_head *list;
- list_for_each (list, &ibmphp_slot_head) {
- slot = list_entry (list, struct slot, ibm_slot_list);
+ list_for_each_entry(slot, &ibmphp_slot_head, ibm_slot_list) {
if (slot->number == physical_num)
return slot;
}
@@ -1120,10 +1077,8 @@ struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num)
struct bus_info *ibmphp_find_same_bus_num (u32 num)
{
struct bus_info *ptr;
- struct list_head *ptr1;
- list_for_each (ptr1, &bus_info_head) {
- ptr = list_entry (ptr1, struct bus_info, bus_info_list);
+ list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
if (ptr->busno == num)
return ptr;
}
@@ -1136,10 +1091,8 @@ struct bus_info *ibmphp_find_same_bus_num (u32 num)
int ibmphp_get_bus_index (u8 num)
{
struct bus_info *ptr;
- struct list_head *ptr1;
- list_for_each (ptr1, &bus_info_head) {
- ptr = list_entry (ptr1, struct bus_info, bus_info_list);
+ list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
if (ptr->busno == num)
return ptr->index;
}
@@ -1212,11 +1165,9 @@ static struct pci_driver ibmphp_driver = {
int ibmphp_register_pci (void)
{
struct controller *ctrl;
- struct list_head *tmp;
int rc = 0;
- list_for_each (tmp, &ebda_hpc_head) {
- ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
+ list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
if (ctrl->ctlr_type == 1) {
rc = pci_register_driver(&ibmphp_driver);
break;
@@ -1227,12 +1178,10 @@ int ibmphp_register_pci (void)
static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids)
{
struct controller *ctrl;
- struct list_head *tmp;
debug ("inside ibmphp_probe\n");
- list_for_each (tmp, &ebda_hpc_head) {
- ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
+ list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
if (ctrl->ctlr_type == 1) {
if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) {
ctrl->ctrl_dev = dev;
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 5f85b1b120e..535fce0f07f 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -37,6 +37,7 @@
#include <linux/init.h>
#include <linux/mount.h>
#include <linux/namei.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <asm/uaccess.h>
@@ -61,7 +62,7 @@ static int debug;
//////////////////////////////////////////////////////////////////
static LIST_HEAD(pci_hotplug_slot_list);
-static DEFINE_SPINLOCK(pci_hotplug_slot_list_lock);
+static DEFINE_MUTEX(pci_hp_mutex);
/* these strings match up with the values in pci_bus_speed */
static char *pci_bus_speed_strings[] = {
@@ -102,13 +103,13 @@ static int get_##name (struct hotplug_slot *slot, type *value) \
{ \
struct hotplug_slot_ops *ops = slot->ops; \
int retval = 0; \
- if (try_module_get(ops->owner)) { \
- if (ops->get_##name) \
- retval = ops->get_##name(slot, value); \
- else \
- *value = slot->info->name; \
- module_put(ops->owner); \
- } \
+ if (!try_module_get(ops->owner)) \
+ return -ENODEV; \
+ if (ops->get_##name) \
+ retval = ops->get_##name(slot, value); \
+ else \
+ *value = slot->info->name; \
+ module_put(ops->owner); \
return retval; \
}
@@ -530,16 +531,12 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
struct hotplug_slot *slot;
struct list_head *tmp;
- spin_lock(&pci_hotplug_slot_list_lock);
list_for_each (tmp, &pci_hotplug_slot_list) {
slot = list_entry (tmp, struct hotplug_slot, slot_list);
- if (strcmp(slot->name, name) == 0)
- goto out;
+ if (strcmp(hotplug_slot_name(slot), name) == 0)
+ return slot;
}
- slot = NULL;
-out:
- spin_unlock(&pci_hotplug_slot_list_lock);
- return slot;
+ return NULL;
}
/**
@@ -547,13 +544,15 @@ out:
* @bus: bus this slot is on
* @slot: pointer to the &struct hotplug_slot to register
* @slot_nr: slot number
+ * @name: name registered with kobject core
*
* Registers a hotplug slot with the pci hotplug subsystem, which will allow
* userspace interaction to the slot.
*
* Returns 0 if successful, anything else for an error.
*/
-int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
+int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
+ const char *name)
{
int result;
struct pci_slot *pci_slot;
@@ -568,48 +567,29 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
return -EINVAL;
}
- /* Check if we have already registered a slot with the same name. */
- if (get_slot_from_name(slot->name))
- return -EEXIST;
+ mutex_lock(&pci_hp_mutex);
/*
* No problems if we call this interface from both ACPI_PCI_SLOT
* driver and call it here again. If we've already created the
* pci_slot, the interface will simply bump the refcount.
*/
- pci_slot = pci_create_slot(bus, slot_nr, slot->name);
- if (IS_ERR(pci_slot))
- return PTR_ERR(pci_slot);
-
- if (pci_slot->hotplug) {
- dbg("%s: already claimed\n", __func__);
- pci_destroy_slot(pci_slot);
- return -EBUSY;
+ pci_slot = pci_create_slot(bus, slot_nr, name, slot);
+ if (IS_ERR(pci_slot)) {
+ result = PTR_ERR(pci_slot);
+ goto out;
}
slot->pci_slot = pci_slot;
pci_slot->hotplug = slot;
- /*
- * Allow pcihp drivers to override the ACPI_PCI_SLOT name.
- */
- if (strcmp(kobject_name(&pci_slot->kobj), slot->name)) {
- result = kobject_rename(&pci_slot->kobj, slot->name);
- if (result) {
- pci_destroy_slot(pci_slot);
- return result;
- }
- }
-
- spin_lock(&pci_hotplug_slot_list_lock);
list_add(&slot->slot_list, &pci_hotplug_slot_list);
- spin_unlock(&pci_hotplug_slot_list_lock);
result = fs_add_slot(pci_slot);
kobject_uevent(&pci_slot->kobj, KOBJ_ADD);
- dbg("Added slot %s to the list\n", slot->name);
-
-
+ dbg("Added slot %s to the list\n", name);
+out:
+ mutex_unlock(&pci_hp_mutex);
return result;
}
@@ -630,21 +610,23 @@ int pci_hp_deregister(struct hotplug_slot *hotplug)
if (!hotplug)
return -ENODEV;
- temp = get_slot_from_name(hotplug->name);
- if (temp != hotplug)
+ mutex_lock(&pci_hp_mutex);
+ temp = get_slot_from_name(hotplug_slot_name(hotplug));
+ if (temp != hotplug) {
+ mutex_unlock(&pci_hp_mutex);
return -ENODEV;
+ }
- spin_lock(&pci_hotplug_slot_list_lock);
list_del(&hotplug->slot_list);
- spin_unlock(&pci_hotplug_slot_list_lock);
slot = hotplug->pci_slot;
fs_remove_slot(slot);
- dbg("Removed slot %s from the list\n", hotplug->name);
+ dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug));
hotplug->release(hotplug);
slot->hotplug = NULL;
pci_destroy_slot(slot);
+ mutex_unlock(&pci_hp_mutex);
return 0;
}
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 9e6cec67e1c..a4817a841fa 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -57,19 +57,30 @@ extern struct workqueue_struct *pciehp_wq;
#define warn(format, arg...) \
printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+#define ctrl_dbg(ctrl, format, arg...) \
+ do { \
+ if (pciehp_debug) \
+ dev_printk(, &ctrl->pcie->device, \
+ format, ## arg); \
+ } while (0)
+#define ctrl_err(ctrl, format, arg...) \
+ dev_err(&ctrl->pcie->device, format, ## arg)
+#define ctrl_info(ctrl, format, arg...) \
+ dev_info(&ctrl->pcie->device, format, ## arg)
+#define ctrl_warn(ctrl, format, arg...) \
+ dev_warn(&ctrl->pcie->device, format, ## arg)
+
#define SLOT_NAME_SIZE 10
struct slot {
u8 bus;
u8 device;
- u32 number;
u8 state;
- struct timer_list task_event;
u8 hp_slot;
+ u32 number;
struct controller *ctrl;
struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
struct list_head slot_list;
- char name[SLOT_NAME_SIZE];
unsigned long last_emi_toggle;
struct delayed_work work; /* work for button event */
struct mutex lock;
@@ -87,6 +98,7 @@ struct controller {
int num_slots; /* Number of slots on ctlr */
int slot_num_inc; /* 1 or -1 */
struct pci_dev *pci_dev;
+ struct pcie_device *pcie; /* PCI Express port service */
struct list_head slot_list;
struct hpc_ops *hpc_ops;
wait_queue_head_t queue; /* sleep & wake process */
@@ -98,6 +110,7 @@ struct controller {
struct timer_list poll_timer;
int cmd_busy;
unsigned int no_cmd_complete:1;
+ unsigned int link_active_reporting:1;
};
#define INT_BUTTON_IGNORE 0
@@ -161,6 +174,11 @@ int pciehp_enable_slot(struct slot *p_slot);
int pciehp_disable_slot(struct slot *p_slot);
int pcie_enable_notification(struct controller *ctrl);
+static inline const char *slot_name(struct slot *slot)
+{
+ return hotplug_slot_name(slot->hotplug_slot);
+}
+
static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
{
struct slot *slot;
@@ -170,7 +188,7 @@ static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
return slot;
}
- err("%s: slot (device=0x%x) not found\n", __func__, device);
+ ctrl_err(ctrl, "%s: slot (device=0x%x) not found\n", __func__, device);
return NULL;
}
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 4fd5355bc3b..62be1b59c74 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -144,9 +144,10 @@ set_lock_exit:
* sysfs interface which allows the user to toggle the Electro Mechanical
* Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock
*/
-static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf,
- size_t count)
+static ssize_t lock_write_file(struct hotplug_slot *hotplug_slot,
+ const char *buf, size_t count)
{
+ struct slot *slot = hotplug_slot->private;
unsigned long llock;
u8 lock;
int retval = 0;
@@ -157,10 +158,11 @@ static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf,
switch (lock) {
case 0:
case 1:
- retval = set_lock_status(slot, lock);
+ retval = set_lock_status(hotplug_slot, lock);
break;
default:
- err ("%d is an invalid lock value\n", lock);
+ ctrl_err(slot->ctrl, "%d is an invalid lock value\n",
+ lock);
retval = -EINVAL;
}
if (retval)
@@ -180,7 +182,10 @@ static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
*/
static void release_slot(struct hotplug_slot *hotplug_slot)
{
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ struct slot *slot = hotplug_slot->private;
+
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, hotplug_slot_name(hotplug_slot));
kfree(hotplug_slot->info);
kfree(hotplug_slot);
@@ -191,7 +196,7 @@ static int init_slots(struct controller *ctrl)
struct slot *slot;
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *info;
- int len, dup = 1;
+ char name[SLOT_NAME_SIZE];
int retval = -ENOMEM;
list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
@@ -205,46 +210,36 @@ static int init_slots(struct controller *ctrl)
/* register this slot with the hotplug pci core */
hotplug_slot->info = info;
- hotplug_slot->name = slot->name;
hotplug_slot->private = slot;
hotplug_slot->release = &release_slot;
hotplug_slot->ops = &pciehp_hotplug_slot_ops;
- get_power_status(hotplug_slot, &info->power_status);
- get_attention_status(hotplug_slot, &info->attention_status);
- get_latch_status(hotplug_slot, &info->latch_status);
- get_adapter_status(hotplug_slot, &info->adapter_status);
slot->hotplug_slot = hotplug_slot;
+ snprintf(name, SLOT_NAME_SIZE, "%u", slot->number);
- dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
- "slot_device_offset=%x\n", slot->bus, slot->device,
- slot->hp_slot, slot->number, ctrl->slot_device_offset);
-duplicate_name:
+ ctrl_dbg(ctrl, "Registering bus=%x dev=%x hp_slot=%x sun=%x "
+ "slot_device_offset=%x\n", slot->bus, slot->device,
+ slot->hp_slot, slot->number, ctrl->slot_device_offset);
retval = pci_hp_register(hotplug_slot,
ctrl->pci_dev->subordinate,
- slot->device);
+ slot->device,
+ name);
if (retval) {
- /*
- * If slot N already exists, we'll try to create
- * slot N-1, N-2 ... N-M, until we overflow.
- */
- if (retval == -EEXIST) {
- len = snprintf(slot->name, SLOT_NAME_SIZE,
- "%d-%d", slot->number, dup++);
- if (len < SLOT_NAME_SIZE)
- goto duplicate_name;
- else
- err("duplicate slot name overflow\n");
- }
- err("pci_hp_register failed with error %d\n", retval);
+ ctrl_err(ctrl, "pci_hp_register failed with error %d\n",
+ retval);
goto error_info;
}
+ get_power_status(hotplug_slot, &info->power_status);
+ get_attention_status(hotplug_slot, &info->attention_status);
+ get_latch_status(hotplug_slot, &info->latch_status);
+ get_adapter_status(hotplug_slot, &info->adapter_status);
/* create additional sysfs entries */
if (EMI(ctrl)) {
retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj,
&hotplug_slot_attr_lock.attr);
if (retval) {
pci_hp_deregister(hotplug_slot);
- err("cannot create additional sysfs entries\n");
+ ctrl_err(ctrl, "cannot create additional sysfs "
+ "entries\n");
goto error_info;
}
}
@@ -278,7 +273,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, slot_name(slot));
hotplug_slot->info->attention_status = status;
@@ -293,7 +289,8 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, slot_name(slot));
return pciehp_sysfs_enable_slot(slot);
}
@@ -303,7 +300,8 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, slot_name(slot));
return pciehp_sysfs_disable_slot(slot);
}
@@ -313,7 +311,8 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = hotplug_slot->private;
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, slot_name(slot));
retval = slot->hpc_ops->get_power_status(slot, value);
if (retval < 0)
@@ -327,7 +326,8 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = hotplug_slot->private;
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, slot_name(slot));
retval = slot->hpc_ops->get_attention_status(slot, value);
if (retval < 0)
@@ -341,7 +341,8 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = hotplug_slot->private;
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, slot_name(slot));
retval = slot->hpc_ops->get_latch_status(slot, value);
if (retval < 0)
@@ -355,7 +356,8 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = hotplug_slot->private;
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, slot_name(slot));
retval = slot->hpc_ops->get_adapter_status(slot, value);
if (retval < 0)
@@ -370,7 +372,8 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot,
struct slot *slot = hotplug_slot->private;
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, slot_name(slot));
retval = slot->hpc_ops->get_max_bus_speed(slot, value);
if (retval < 0)
@@ -384,7 +387,8 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
struct slot *slot = hotplug_slot->private;
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n",
+ __func__, slot_name(slot));
retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
if (retval < 0)
@@ -402,14 +406,15 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
struct pci_dev *pdev = dev->port;
if (pciehp_force)
- dbg("Bypassing BIOS check for pciehp use on %s\n",
- pci_name(pdev));
+ dev_info(&dev->device,
+ "Bypassing BIOS check for pciehp use on %s\n",
+ pci_name(pdev));
else if (pciehp_get_hp_hw_control_from_firmware(pdev))
goto err_out_none;
ctrl = pcie_init(dev);
if (!ctrl) {
- dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME);
+ dev_err(&dev->device, "controller initialization failed\n");
goto err_out_none;
}
set_service_data(dev, ctrl);
@@ -418,11 +423,10 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
rc = init_slots(ctrl);
if (rc) {
if (rc == -EBUSY)
- warn("%s: slot already registered by another "
- "hotplug driver\n", PCIE_MODULE_NAME);
+ ctrl_warn(ctrl, "slot already registered by another "
+ "hotplug driver\n");
else
- err("%s: slot initialization failed\n",
- PCIE_MODULE_NAME);
+ ctrl_err(ctrl, "slot initialization failed\n");
goto err_out_release_ctlr;
}
@@ -461,13 +465,13 @@ static void pciehp_remove (struct pcie_device *dev)
#ifdef CONFIG_PM
static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
{
- printk("%s ENTRY\n", __func__);
+ dev_info(&dev->device, "%s ENTRY\n", __func__);
return 0;
}
static int pciehp_resume (struct pcie_device *dev)
{
- printk("%s ENTRY\n", __func__);
+ dev_info(&dev->device, "%s ENTRY\n", __func__);
if (pciehp_force) {
struct controller *ctrl = get_service_data(dev);
struct slot *t_slot;
@@ -497,10 +501,9 @@ static struct pcie_port_service_id port_pci_ids[] = { {
.driver_data = 0,
}, { /* end: all zeroes */ }
};
-static const char device_name[] = "hpdriver";
static struct pcie_port_service_driver hpdriver_portdrv = {
- .name = (char *)device_name,
+ .name = PCIE_MODULE_NAME,
.id_table = &port_pci_ids[0],
.probe = pciehp_probe,
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 96a5d55a498..d6c5eb29775 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -58,14 +58,15 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
u8 pciehp_handle_attention_button(struct slot *p_slot)
{
u32 event_type;
+ struct controller *ctrl = p_slot->ctrl;
/* Attention Button Change */
- dbg("pciehp: Attention button interrupt received.\n");
+ ctrl_dbg(ctrl, "Attention button interrupt received.\n");
/*
* Button pressed - See if need to TAKE ACTION!!!
*/
- info("Button pressed on Slot(%s)\n", p_slot->name);
+ ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot));
event_type = INT_BUTTON_PRESS;
queue_interrupt_event(p_slot, event_type);
@@ -77,22 +78,23 @@ u8 pciehp_handle_switch_change(struct slot *p_slot)
{
u8 getstatus;
u32 event_type;
+ struct controller *ctrl = p_slot->ctrl;
/* Switch Change */
- dbg("pciehp: Switch interrupt received.\n");
+ ctrl_dbg(ctrl, "Switch interrupt received.\n");
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (getstatus) {
/*
* Switch opened
*/
- info("Latch open on Slot(%s)\n", p_slot->name);
+ ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot));
event_type = INT_SWITCH_OPEN;
} else {
/*
* Switch closed
*/
- info("Latch close on Slot(%s)\n", p_slot->name);
+ ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot));
event_type = INT_SWITCH_CLOSE;
}
@@ -105,9 +107,10 @@ u8 pciehp_handle_presence_change(struct slot *p_slot)
{
u32 event_type;
u8 presence_save;
+ struct controller *ctrl = p_slot->ctrl;
/* Presence Change */
- dbg("pciehp: Presence/Notify input change.\n");
+ ctrl_dbg(ctrl, "Presence/Notify input change.\n");
/* Switch is open, assume a presence change
* Save the presence state
@@ -117,13 +120,14 @@ u8 pciehp_handle_presence_change(struct slot *p_slot)
/*
* Card Present
*/
- info("Card present on Slot(%s)\n", p_slot->name);
+ ctrl_info(ctrl, "Card present on Slot(%s)\n", slot_name(p_slot));
event_type = INT_PRESENCE_ON;
} else {
/*
* Not Present
*/
- info("Card not present on Slot(%s)\n", p_slot->name);
+ ctrl_info(ctrl, "Card not present on Slot(%s)\n",
+ slot_name(p_slot));
event_type = INT_PRESENCE_OFF;
}
@@ -135,23 +139,25 @@ u8 pciehp_handle_presence_change(struct slot *p_slot)
u8 pciehp_handle_power_fault(struct slot *p_slot)
{
u32 event_type;
+ struct controller *ctrl = p_slot->ctrl;
/* power fault */
- dbg("pciehp: Power fault interrupt received.\n");
+ ctrl_dbg(ctrl, "Power fault interrupt received.\n");
if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
/*
* power fault Cleared
*/
- info("Power fault cleared on Slot(%s)\n", p_slot->name);
+ ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n",
+ slot_name(p_slot));
event_type = INT_POWER_FAULT_CLEAR;
} else {
/*
* power fault
*/
- info("Power fault on Slot(%s)\n", p_slot->name);
+ ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot));
event_type = INT_POWER_FAULT;
- info("power fault bit %x set\n", 0);
+ ctrl_info(ctrl, "power fault bit %x set\n", 0);
}
queue_interrupt_event(p_slot, event_type);
@@ -168,8 +174,9 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl)) {
if (pslot->hpc_ops->power_off_slot(pslot)) {
- err("%s: Issue of Slot Power Off command failed\n",
- __func__);
+ ctrl_err(ctrl,
+ "%s: Issue of Slot Power Off command failed\n",
+ __func__);
return;
}
}
@@ -186,8 +193,8 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
if (ATTN_LED(ctrl)) {
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
- err("%s: Issue of Set Attention Led command failed\n",
- __func__);
+ ctrl_err(ctrl, "%s: Issue of Set Attention "
+ "Led command failed\n", __func__);
return;
}
}
@@ -205,9 +212,9 @@ static int board_added(struct slot *p_slot)
int retval = 0;
struct controller *ctrl = p_slot->ctrl;
- dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
- __func__, p_slot->device,
- ctrl->slot_device_offset, p_slot->hp_slot);
+ ctrl_dbg(ctrl, "%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
+ __func__, p_slot->device, ctrl->slot_device_offset,
+ p_slot->hp_slot);
if (POWER_CTRL(ctrl)) {
/* Power on slot */
@@ -219,28 +226,25 @@ static int board_added(struct slot *p_slot)
if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_blink(p_slot);
- /* Wait for ~1 second */
- msleep(1000);
-
/* Check link training status */
retval = p_slot->hpc_ops->check_lnk_status(ctrl);
if (retval) {
- err("%s: Failed to check link status\n", __func__);
+ ctrl_err(ctrl, "%s: Failed to check link status\n", __func__);
set_slot_off(ctrl, p_slot);
return retval;
}
/* Check for a power fault */
if (p_slot->hpc_ops->query_power_fault(p_slot)) {
- dbg("%s: power fault detected\n", __func__);
+ ctrl_dbg(ctrl, "%s: power fault detected\n", __func__);
retval = POWER_FAILURE;
goto err_exit;
}
retval = pciehp_configure_device(p_slot);
if (retval) {
- err("Cannot add device 0x%x:%x\n", p_slot->bus,
- p_slot->device);
+ ctrl_err(ctrl, "Cannot add device 0x%x:%x\n",
+ p_slot->bus, p_slot->device);
goto err_exit;
}
@@ -272,14 +276,14 @@ static int remove_board(struct slot *p_slot)
if (retval)
return retval;
- dbg("In %s, hp_slot = %d\n", __func__, p_slot->hp_slot);
+ ctrl_dbg(ctrl, "In %s, hp_slot = %d\n", __func__, p_slot->hp_slot);
if (POWER_CTRL(ctrl)) {
/* power off slot */
retval = p_slot->hpc_ops->power_off_slot(p_slot);
if (retval) {
- err("%s: Issue of Slot Disable command failed\n",
- __func__);
+ ctrl_err(ctrl, "%s: Issue of Slot Disable command "
+ "failed\n", __func__);
return retval;
}
}
@@ -320,8 +324,8 @@ static void pciehp_power_thread(struct work_struct *work)
switch (p_slot->state) {
case POWEROFF_STATE:
mutex_unlock(&p_slot->lock);
- dbg("%s: disabling bus:device(%x:%x)\n",
- __func__, p_slot->bus, p_slot->device);
+ ctrl_dbg(p_slot->ctrl, "%s: disabling bus:device(%x:%x)\n",
+ __func__, p_slot->bus, p_slot->device);
pciehp_disable_slot(p_slot);
mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
@@ -349,7 +353,8 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
- err("%s: Cannot allocate memory\n", __func__);
+ ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
+ __func__);
return;
}
info->p_slot = p_slot;
@@ -403,12 +408,14 @@ static void handle_button_press_event(struct slot *p_slot)
p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (getstatus) {
p_slot->state = BLINKINGOFF_STATE;
- info("PCI slot #%s - powering off due to button "
- "press.\n", p_slot->name);
+ ctrl_info(ctrl,
+ "PCI slot #%s - powering off due to button "
+ "press.\n", slot_name(p_slot));
} else {
p_slot->state = BLINKINGON_STATE;
- info("PCI slot #%s - powering on due to button "
- "press.\n", p_slot->name);
+ ctrl_info(ctrl,
+ "PCI slot #%s - powering on due to button "
+ "press.\n", slot_name(p_slot));
}
/* blink green LED and turn off amber */
if (PWR_LED(ctrl))
@@ -425,8 +432,8 @@ static void handle_button_press_event(struct slot *p_slot)
* press the attention again before the 5 sec. limit
* expires to cancel hot-add or hot-remove
*/
- info("Button cancel on Slot(%s)\n", p_slot->name);
- dbg("%s: button cancel\n", __func__);
+ ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
+ ctrl_dbg(ctrl, "%s: button cancel\n", __func__);
cancel_delayed_work(&p_slot->work);
if (p_slot->state == BLINKINGOFF_STATE) {
if (PWR_LED(ctrl))
@@ -437,8 +444,8 @@ static void handle_button_press_event(struct slot *p_slot)
}
if (ATTN_LED(ctrl))
p_slot->hpc_ops->set_attention_status(p_slot, 0);
- info("PCI slot #%s - action canceled due to button press\n",
- p_slot->name);
+ ctrl_info(ctrl, "PCI slot #%s - action canceled "
+ "due to button press\n", slot_name(p_slot));
p_slot->state = STATIC_STATE;
break;
case POWEROFF_STATE:
@@ -448,11 +455,11 @@ static void handle_button_press_event(struct slot *p_slot)
* this means that the previous attention button action
* to hot-add or hot-remove is undergoing
*/
- info("Button ignore on Slot(%s)\n", p_slot->name);
+ ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot));
update_slot_info(p_slot);
break;
default:
- warn("Not a valid state\n");
+ ctrl_warn(ctrl, "Not a valid state\n");
break;
}
}
@@ -467,7 +474,8 @@ static void handle_surprise_event(struct slot *p_slot)
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
- err("%s: Cannot allocate memory\n", __func__);
+ ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
+ __func__);
return;
}
info->p_slot = p_slot;
@@ -505,7 +513,7 @@ static void interrupt_event_handler(struct work_struct *work)
case INT_PRESENCE_OFF:
if (!HP_SUPR_RM(ctrl))
break;
- dbg("Surprise Removal\n");
+ ctrl_dbg(ctrl, "Surprise Removal\n");
update_slot_info(p_slot);
handle_surprise_event(p_slot);
break;
@@ -522,22 +530,23 @@ int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
int rc;
+ struct controller *ctrl = p_slot->ctrl;
/* Check to see if (latch closed, card present, power off) */
mutex_lock(&p_slot->ctrl->crit_sect);
rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) {
- info("%s: no adapter on slot(%s)\n", __func__,
- p_slot->name);
+ ctrl_info(ctrl, "%s: no adapter on slot(%s)\n",
+ __func__, slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
if (MRL_SENS(p_slot->ctrl)) {
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
- info("%s: latch open on slot(%s)\n", __func__,
- p_slot->name);
+ ctrl_info(ctrl, "%s: latch open on slot(%s)\n",
+ __func__, slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@@ -546,8 +555,8 @@ int pciehp_enable_slot(struct slot *p_slot)
if (POWER_CTRL(p_slot->ctrl)) {
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
- info("%s: already enabled on slot(%s)\n", __func__,
- p_slot->name);
+ ctrl_info(ctrl, "%s: already enabled on slot(%s)\n",
+ __func__, slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -EINVAL;
}
@@ -571,6 +580,7 @@ int pciehp_disable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
int ret = 0;
+ struct controller *ctrl = p_slot->ctrl;
if (!p_slot->ctrl)
return 1;
@@ -581,8 +591,8 @@ int pciehp_disable_slot(struct slot *p_slot)
if (!HP_SUPR_RM(p_slot->ctrl)) {
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) {
- info("%s: no adapter on slot(%s)\n", __func__,
- p_slot->name);
+ ctrl_info(ctrl, "%s: no adapter on slot(%s)\n",
+ __func__, slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@@ -591,8 +601,8 @@ int pciehp_disable_slot(struct slot *p_slot)
if (MRL_SENS(p_slot->ctrl)) {
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
- info("%s: latch open on slot(%s)\n", __func__,
- p_slot->name);
+ ctrl_info(ctrl, "%s: latch open on slot(%s)\n",
+ __func__, slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@@ -601,8 +611,8 @@ int pciehp_disable_slot(struct slot *p_slot)
if (POWER_CTRL(p_slot->ctrl)) {
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
- info("%s: already disabled slot(%s)\n", __func__,
- p_slot->name);
+ ctrl_info(ctrl, "%s: already disabled slot(%s)\n",
+ __func__, slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -EINVAL;
}
@@ -618,6 +628,7 @@ int pciehp_disable_slot(struct slot *p_slot)
int pciehp_sysfs_enable_slot(struct slot *p_slot)
{
int retval = -ENODEV;
+ struct controller *ctrl = p_slot->ctrl;
mutex_lock(&p_slot->lock);
switch (p_slot->state) {
@@ -631,15 +642,17 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
p_slot->state = STATIC_STATE;
break;
case POWERON_STATE:
- info("Slot %s is already in powering on state\n",
- p_slot->name);
+ ctrl_info(ctrl, "Slot %s is already in powering on state\n",
+ slot_name(p_slot));
break;
case BLINKINGOFF_STATE:
case POWEROFF_STATE:
- info("Already enabled on slot %s\n", p_slot->name);
+ ctrl_info(ctrl, "Already enabled on slot %s\n",
+ slot_name(p_slot));
break;
default:
- err("Not a valid state on slot %s\n", p_slot->name);
+ ctrl_err(ctrl, "Not a valid state on slot %s\n",
+ slot_name(p_slot));
break;
}
mutex_unlock(&p_slot->lock);
@@ -650,6 +663,7 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
int pciehp_sysfs_disable_slot(struct slot *p_slot)
{
int retval = -ENODEV;
+ struct controller *ctrl = p_slot->ctrl;
mutex_lock(&p_slot->lock);
switch (p_slot->state) {
@@ -663,15 +677,17 @@ int pciehp_sysfs_disable_slot(struct slot *p_slot)
p_slot->state = STATIC_STATE;
break;
case POWEROFF_STATE:
- info("Slot %s is already in powering off state\n",
- p_slot->name);
+ ctrl_info(ctrl, "Slot %s is already in powering off state\n",
+ slot_name(p_slot));
break;
case BLINKINGON_STATE:
case POWERON_STATE:
- info("Already disabled on slot %s\n", p_slot->name);
+ ctrl_info(ctrl, "Already disabled on slot %s\n",
+ slot_name(p_slot));
break;
default:
- err("Not a valid state on slot %s\n", p_slot->name);
+ ctrl_err(ctrl, "Not a valid state on slot %s\n",
+ slot_name(p_slot));
break;
}
mutex_unlock(&p_slot->lock);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 9d934ddee95..58c72d2cc21 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -125,6 +125,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
/* 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
@@ -141,6 +142,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
#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
@@ -223,7 +225,7 @@ static void start_int_poll_timer(struct controller *ctrl, int sec)
static inline int pciehp_request_irq(struct controller *ctrl)
{
- int retval, irq = ctrl->pci_dev->irq;
+ int retval, irq = ctrl->pcie->irq;
/* Install interrupt polling timer. Start with 10 sec delay */
if (pciehp_poll_mode) {
@@ -235,7 +237,8 @@ static inline int pciehp_request_irq(struct controller *ctrl)
/* Installs the interrupt handler */
retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl);
if (retval)
- err("Cannot get irq %d for the hotplug controller\n", irq);
+ ctrl_err(ctrl, "Cannot get irq %d for the hotplug controller\n",
+ irq);
return retval;
}
@@ -244,7 +247,7 @@ static inline void pciehp_free_irq(struct controller *ctrl)
if (pciehp_poll_mode)
del_timer_sync(&ctrl->poll_timer);
else
- free_irq(ctrl->pci_dev->irq, ctrl);
+ free_irq(ctrl->pcie->irq, ctrl);
}
static int pcie_poll_cmd(struct controller *ctrl)
@@ -282,7 +285,7 @@ static void pcie_wait_cmd(struct controller *ctrl, int poll)
else
rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout);
if (!rc)
- dbg("Command not completed in 1000 msec\n");
+ ctrl_dbg(ctrl, "Command not completed in 1000 msec\n");
}
/**
@@ -301,7 +304,8 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
+ __func__);
goto out;
}
@@ -312,26 +316,28 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
* proceed forward to issue the next command according
* to spec. Just print out the error message.
*/
- dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
- __func__);
+ ctrl_dbg(ctrl,
+ "%s: CMD_COMPLETED not clear after 1 sec.\n",
+ __func__);
} else if (!NO_CMD_CMPL(ctrl)) {
/*
* This controller semms to notify of command completed
* event even though it supports none of power
* controller, attention led, power led and EMI.
*/
- dbg("%s: Unexpected CMD_COMPLETED. Need to wait for "
- "command completed event.\n", __func__);
+ ctrl_dbg(ctrl, "%s: Unexpected CMD_COMPLETED. Need to "
+ "wait for command completed event.\n",
+ __func__);
ctrl->no_cmd_complete = 0;
} else {
- dbg("%s: Unexpected CMD_COMPLETED. Maybe the "
- "controller is broken.\n", __func__);
+ ctrl_dbg(ctrl, "%s: Unexpected CMD_COMPLETED. Maybe "
+ "the controller is broken.\n", __func__);
}
}
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s: Cannot read SLOTCTRL register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
goto out;
}
@@ -341,7 +347,8 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
smp_mb();
retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl);
if (retval)
- err("%s: Cannot write to SLOTCTRL register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot write to SLOTCTRL register\n",
+ __func__);
/*
* Wait for command completion.
@@ -363,21 +370,63 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
return retval;
}
+static inline int check_link_active(struct controller *ctrl)
+{
+ u16 link_status;
+
+ if (pciehp_readw(ctrl, LNKSTATUS, &link_status))
+ return 0;
+ return !!(link_status & LINK_ACTIVE);
+}
+
+static void pcie_wait_link_active(struct controller *ctrl)
+{
+ int timeout = 1000;
+
+ if (check_link_active(ctrl))
+ return;
+ while (timeout > 0) {
+ msleep(10);
+ timeout -= 10;
+ if (check_link_active(ctrl))
+ return;
+ }
+ ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n");
+}
+
static int hpc_check_lnk_status(struct controller *ctrl)
{
u16 lnk_status;
int retval = 0;
+ /*
+ * Data Link Layer Link Active Reporting must be capable for
+ * hot-plug capable downstream port. But old controller might
+ * not implement it. In this case, we wait for 1000 ms.
+ */
+ if (ctrl->link_active_reporting){
+ /* Wait for Data Link Layer Link Active bit to be set */
+ pcie_wait_link_active(ctrl);
+ /*
+ * We must wait for 100 ms after the Data Link Layer
+ * Link Active bit reads 1b before initiating a
+ * configuration access to the hot added device.
+ */
+ msleep(100);
+ } else
+ msleep(1000);
+
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s: Cannot read LNKSTATUS register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n",
+ __func__);
return retval;
}
- dbg("%s: lnk_status = %x\n", __func__, lnk_status);
+ 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)) {
- err("%s : Link Training Error occurs \n", __func__);
+ ctrl_err(ctrl, "%s : Link Training Error occurs \n", __func__);
retval = -1;
return retval;
}
@@ -394,12 +443,12 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s: Cannot read SLOTCTRL register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
return retval;
}
- dbg("%s: SLOTCTRL %x, value read %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
+ ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n",
+ __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
@@ -433,11 +482,11 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s: Cannot read SLOTCTRL register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
return retval;
}
- dbg("%s: SLOTCTRL %x value read %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
+ ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n",
+ __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
@@ -464,7 +513,8 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status)
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
+ __func__);
return retval;
}
@@ -482,7 +532,8 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
+ __func__);
return retval;
}
card_state = (u8)((slot_status & PRSN_STATE) >> 6);
@@ -500,7 +551,7 @@ static int hpc_query_power_fault(struct slot *slot)
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s: Cannot check for power fault\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot check for power fault\n", __func__);
return retval;
}
pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
@@ -516,7 +567,7 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : Cannot check EMI status\n", __func__);
+ ctrl_err(ctrl, "%s : Cannot check EMI status\n", __func__);
return retval;
}
*status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
@@ -560,8 +611,8 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
return -1;
}
rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
- dbg("%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
+ __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
return rc;
}
@@ -575,8 +626,8 @@ static void hpc_set_green_led_on(struct slot *slot)
slot_cmd = 0x0100;
cmd_mask = PWR_LED_CTRL;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
- dbg("%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
+ __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
}
static void hpc_set_green_led_off(struct slot *slot)
@@ -588,8 +639,8 @@ static void hpc_set_green_led_off(struct slot *slot)
slot_cmd = 0x0300;
cmd_mask = PWR_LED_CTRL;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
- dbg("%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
+ __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
}
static void hpc_set_green_led_blink(struct slot *slot)
@@ -601,8 +652,8 @@ static void hpc_set_green_led_blink(struct slot *slot)
slot_cmd = 0x0200;
cmd_mask = PWR_LED_CTRL;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
- dbg("%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
+ __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
}
static int hpc_power_on_slot(struct slot * slot)
@@ -613,20 +664,22 @@ static int hpc_power_on_slot(struct slot * slot)
u16 slot_status;
int retval = 0;
- dbg("%s: slot->hp_slot %x\n", __func__, slot->hp_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);
if (retval) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
+ __func__);
return retval;
}
slot_status &= PWR_FAULT_DETECTED;
if (slot_status) {
retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status);
if (retval) {
- err("%s: Cannot write to SLOTSTATUS register\n",
- __func__);
+ ctrl_err(ctrl,
+ "%s: Cannot write to SLOTSTATUS register\n",
+ __func__);
return retval;
}
}
@@ -644,11 +697,12 @@ static int hpc_power_on_slot(struct slot * slot)
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) {
- err("%s: Write %x command failed!\n", __func__, slot_cmd);
+ ctrl_err(ctrl, "%s: Write %x command failed!\n",
+ __func__, slot_cmd);
return -1;
}
- dbg("%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
+ __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
return retval;
}
@@ -694,7 +748,7 @@ static int hpc_power_off_slot(struct slot * slot)
int retval = 0;
int changed;
- dbg("%s: slot->hp_slot %x\n", __func__, slot->hp_slot);
+ ctrl_dbg(ctrl, "%s: slot->hp_slot %x\n", __func__, slot->hp_slot);
/*
* Set Bad DLLP Mask bit in Correctable Error Mask
@@ -722,12 +776,12 @@ static int hpc_power_off_slot(struct slot * slot)
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) {
- err("%s: Write command failed!\n", __func__);
+ ctrl_err(ctrl, "%s: Write command failed!\n", __func__);
retval = -1;
goto out;
}
- dbg("%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
+ __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
out:
if (changed)
pcie_unmask_bad_dllp(ctrl);
@@ -749,7 +803,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
intr_loc = 0;
do {
if (pciehp_readw(ctrl, SLOTSTATUS, &detected)) {
- err("%s: Cannot read SLOTSTATUS\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS\n",
+ __func__);
return IRQ_NONE;
}
@@ -760,12 +815,13 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
if (!intr_loc)
return IRQ_NONE;
if (detected && pciehp_writew(ctrl, SLOTSTATUS, detected)) {
- err("%s: Cannot write to SLOTSTATUS\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS\n",
+ __func__);
return IRQ_NONE;
}
} while (detected);
- dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
+ ctrl_dbg(ctrl, "%s: intr_loc %x\n", __func__, intr_loc);
/* Check Command Complete Interrupt Pending */
if (intr_loc & CMD_COMPLETED) {
@@ -807,7 +863,7 @@ static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s: Cannot read LNKCAP register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__);
return retval;
}
@@ -821,7 +877,7 @@ static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
}
*value = lnk_speed;
- dbg("Max link speed = %d\n", lnk_speed);
+ ctrl_dbg(ctrl, "Max link speed = %d\n", lnk_speed);
return retval;
}
@@ -836,7 +892,7 @@ static int hpc_get_max_lnk_width(struct slot *slot,
retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s: Cannot read LNKCAP register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__);
return retval;
}
@@ -871,7 +927,7 @@ static int hpc_get_max_lnk_width(struct slot *slot,
}
*value = lnk_wdth;
- dbg("Max link width = %d\n", lnk_wdth);
+ ctrl_dbg(ctrl, "Max link width = %d\n", lnk_wdth);
return retval;
}
@@ -885,7 +941,8 @@ static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s: Cannot read LNKSTATUS register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n",
+ __func__);
return retval;
}
@@ -899,7 +956,7 @@ static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
}
*value = lnk_speed;
- dbg("Current link speed = %d\n", lnk_speed);
+ ctrl_dbg(ctrl, "Current link speed = %d\n", lnk_speed);
return retval;
}
@@ -914,7 +971,8 @@ static int hpc_get_cur_lnk_width(struct slot *slot,
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s: Cannot read LNKSTATUS register\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n",
+ __func__);
return retval;
}
@@ -949,7 +1007,7 @@ static int hpc_get_cur_lnk_width(struct slot *slot,
}
*value = lnk_wdth;
- dbg("Current link width = %d\n", lnk_wdth);
+ ctrl_dbg(ctrl, "Current link width = %d\n", lnk_wdth);
return retval;
}
@@ -998,7 +1056,8 @@ int pcie_enable_notification(struct controller *ctrl)
PWR_FAULT_DETECT_ENABLE | HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE;
if (pcie_write_cmd(ctrl, cmd, mask)) {
- err("%s: Cannot enable software notification\n", __func__);
+ ctrl_err(ctrl, "%s: Cannot enable software notification\n",
+ __func__);
return -1;
}
return 0;
@@ -1010,7 +1069,8 @@ static void pcie_disable_notification(struct controller *ctrl)
mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | MRL_DETECT_ENABLE |
PWR_FAULT_DETECT_ENABLE | HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE;
if (pcie_write_cmd(ctrl, 0, mask))
- warn("%s: Cannot disable software notification\n", __func__);
+ ctrl_warn(ctrl, "%s: Cannot disable software notification\n",
+ __func__);
}
static int pcie_init_notification(struct controller *ctrl)
@@ -1044,7 +1104,6 @@ static int pcie_init_slot(struct controller *ctrl)
slot->device = ctrl->slot_device_offset + slot->hp_slot;
slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot;
- snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number);
mutex_init(&slot->lock);
INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
list_add(&slot->slot_list, &ctrl->slot_list);
@@ -1071,58 +1130,71 @@ static inline void dbg_ctrl(struct controller *ctrl)
if (!pciehp_debug)
return;
- dbg("Hotplug Controller:\n");
- dbg(" Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", pci_name(pdev), pdev->irq);
- dbg(" Vendor ID : 0x%04x\n", pdev->vendor);
- dbg(" Device ID : 0x%04x\n", pdev->device);
- dbg(" Subsystem ID : 0x%04x\n", pdev->subsystem_device);
- dbg(" Subsystem Vendor ID : 0x%04x\n", pdev->subsystem_vendor);
- dbg(" PCIe Cap offset : 0x%02x\n", ctrl->cap_base);
+ ctrl_info(ctrl, "Hotplug Controller:\n");
+ ctrl_info(ctrl, " Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n",
+ pci_name(pdev), pdev->irq);
+ ctrl_info(ctrl, " Vendor ID : 0x%04x\n", pdev->vendor);
+ ctrl_info(ctrl, " Device ID : 0x%04x\n", pdev->device);
+ ctrl_info(ctrl, " Subsystem ID : 0x%04x\n",
+ pdev->subsystem_device);
+ ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n",
+ pdev->subsystem_vendor);
+ ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", ctrl->cap_base);
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
if (!pci_resource_len(pdev, i))
continue;
- dbg(" PCI resource [%d] : 0x%llx@0x%llx\n", i,
- (unsigned long long)pci_resource_len(pdev, i),
- (unsigned long long)pci_resource_start(pdev, i));
+ ctrl_info(ctrl, " PCI resource [%d] : 0x%llx@0x%llx\n",
+ i, (unsigned long long)pci_resource_len(pdev, i),
+ (unsigned long long)pci_resource_start(pdev, i));
}
- dbg("Slot Capabilities : 0x%08x\n", ctrl->slot_cap);
- dbg(" Physical Slot Number : %d\n", ctrl->first_slot);
- dbg(" Attention Button : %3s\n", ATTN_BUTTN(ctrl) ? "yes" : "no");
- dbg(" Power Controller : %3s\n", POWER_CTRL(ctrl) ? "yes" : "no");
- dbg(" MRL Sensor : %3s\n", MRL_SENS(ctrl) ? "yes" : "no");
- dbg(" Attention Indicator : %3s\n", ATTN_LED(ctrl) ? "yes" : "no");
- dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no");
- dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no");
- dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no");
- dbg(" Command Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes");
+ ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap);
+ ctrl_info(ctrl, " Physical Slot Number : %d\n", ctrl->first_slot);
+ ctrl_info(ctrl, " Attention Button : %3s\n",
+ ATTN_BUTTN(ctrl) ? "yes" : "no");
+ ctrl_info(ctrl, " Power Controller : %3s\n",
+ POWER_CTRL(ctrl) ? "yes" : "no");
+ ctrl_info(ctrl, " MRL Sensor : %3s\n",
+ MRL_SENS(ctrl) ? "yes" : "no");
+ ctrl_info(ctrl, " Attention Indicator : %3s\n",
+ ATTN_LED(ctrl) ? "yes" : "no");
+ ctrl_info(ctrl, " Power Indicator : %3s\n",
+ PWR_LED(ctrl) ? "yes" : "no");
+ ctrl_info(ctrl, " Hot-Plug Surprise : %3s\n",
+ HP_SUPR_RM(ctrl) ? "yes" : "no");
+ ctrl_info(ctrl, " EMI Present : %3s\n",
+ EMI(ctrl) ? "yes" : "no");
+ ctrl_info(ctrl, " Command Completed : %3s\n",
+ NO_CMD_CMPL(ctrl) ? "no" : "yes");
pciehp_readw(ctrl, SLOTSTATUS, &reg16);
- dbg("Slot Status : 0x%04x\n", reg16);
+ ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16);
pciehp_readw(ctrl, SLOTCTRL, &reg16);
- dbg("Slot Control : 0x%04x\n", reg16);
+ ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16);
}
struct controller *pcie_init(struct pcie_device *dev)
{
struct controller *ctrl;
- u32 slot_cap;
+ u32 slot_cap, link_cap;
struct pci_dev *pdev = dev->port;
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl) {
- err("%s : out of memory\n", __func__);
+ dev_err(&dev->device, "%s : out of memory\n", __func__);
goto abort;
}
INIT_LIST_HEAD(&ctrl->slot_list);
+ ctrl->pcie = dev;
ctrl->pci_dev = pdev;
ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (!ctrl->cap_base) {
- err("%s: Cannot find PCI Express capability\n", __func__);
- goto abort;
+ ctrl_err(ctrl, "%s: Cannot find PCI Express capability\n",
+ __func__);
+ goto abort_ctrl;
}
if (pciehp_readl(ctrl, SLOTCAP, &slot_cap)) {
- err("%s: Cannot read SLOTCAP register\n", __func__);
- goto abort;
+ ctrl_err(ctrl, "%s: Cannot read SLOTCAP register\n", __func__);
+ goto abort_ctrl;
}
ctrl->slot_cap = slot_cap;
@@ -1144,6 +1216,16 @@ struct controller *pcie_init(struct pcie_device *dev)
!(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl)))
ctrl->no_cmd_complete = 1;
+ /* Check if Data Link Layer Link Active Reporting is implemented */
+ if (pciehp_readl(ctrl, LNKCAP, &link_cap)) {
+ ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__);
+ goto abort_ctrl;
+ }
+ if (link_cap & LINK_ACTIVE_REPORTING) {
+ 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))
goto abort_ctrl;
@@ -1161,9 +1243,9 @@ struct controller *pcie_init(struct pcie_device *dev)
goto abort_ctrl;
}
- info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
- pdev->vendor, pdev->device,
- pdev->subsystem_vendor, pdev->subsystem_device);
+ ctrl_info(ctrl, "HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
+ pdev->vendor, pdev->device, pdev->subsystem_vendor,
+ pdev->subsystem_device);
if (pcie_init_slot(ctrl))
goto abort_ctrl;
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 6040dcceb25..ffd11148fbe 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -198,18 +198,20 @@ int pciehp_configure_device(struct slot *p_slot)
struct pci_dev *dev;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
int num, fn;
+ struct controller *ctrl = p_slot->ctrl;
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
if (dev) {
- err("Device %s already exists at %x:%x, cannot hot-add\n",
- pci_name(dev), p_slot->bus, p_slot->device);
+ ctrl_err(ctrl,
+ "Device %s already exists at %x:%x, cannot hot-add\n",
+ pci_name(dev), p_slot->bus, p_slot->device);
pci_dev_put(dev);
return -EINVAL;
}
num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
if (num == 0) {
- err("No new device found\n");
+ ctrl_err(ctrl, "No new device found\n");
return -ENODEV;
}
@@ -218,8 +220,8 @@ int pciehp_configure_device(struct slot *p_slot)
if (!dev)
continue;
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
- err("Cannot hot-add display device %s\n",
- pci_name(dev));
+ ctrl_err(ctrl, "Cannot hot-add display device %s\n",
+ pci_name(dev));
pci_dev_put(dev);
continue;
}
@@ -244,9 +246,10 @@ int pciehp_unconfigure_device(struct slot *p_slot)
u8 presence = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
u16 command;
+ struct controller *ctrl = p_slot->ctrl;
- dbg("%s: bus/dev = %x/%x\n", __func__, p_slot->bus,
- p_slot->device);
+ ctrl_dbg(ctrl, "%s: bus/dev = %x/%x\n", __func__,
+ p_slot->bus, p_slot->device);
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence);
if (ret)
presence = 0;
@@ -257,16 +260,17 @@ int pciehp_unconfigure_device(struct slot *p_slot)
if (!temp)
continue;
if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
- err("Cannot remove display device %s\n",
- pci_name(temp));
+ ctrl_err(ctrl, "Cannot remove display device %s\n",
+ pci_name(temp));
pci_dev_put(temp);
continue;
}
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
if (bctl & PCI_BRIDGE_CTL_VGA) {
- err("Cannot remove display device %s\n",
- pci_name(temp));
+ ctrl_err(ctrl,
+ "Cannot remove display device %s\n",
+ pci_name(temp));
pci_dev_put(temp);
continue;
}
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
index 7d5921b1ee7..419919a87b0 100644
--- a/drivers/pci/hotplug/rpaphp.h
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -46,10 +46,10 @@
#define PRESENT 1 /* Card in slot */
#define MY_NAME "rpaphp"
-extern int debug;
+extern int rpaphp_debug;
#define dbg(format, arg...) \
do { \
- if (debug) \
+ if (rpaphp_debug) \
printk(KERN_DEBUG "%s: " format, \
MY_NAME , ## arg); \
} while (0)
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index 1f84f402acd..95d02a08fdc 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -37,7 +37,7 @@
/* and pci_do_scan_bus */
#include "rpaphp.h"
-int debug;
+int rpaphp_debug;
LIST_HEAD(rpaphp_slot_head);
#define DRIVER_VERSION "0.1"
@@ -50,7 +50,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param(debug, bool, 0644);
+module_param_named(debug, rpaphp_debug, bool, 0644);
/**
* set_attention_status - set attention LED
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
index 5acfd4f3d4c..513e1e28239 100644
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -123,7 +123,7 @@ int rpaphp_enable_slot(struct slot *slot)
slot->state = CONFIGURED;
}
- if (debug) {
+ if (rpaphp_debug) {
struct pci_dev *dev;
dbg("%s: pci_devs of slot[%s]\n", __func__, slot->dn->full_name);
list_for_each_entry (dev, &bus->devices, bus_list)
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
index 50884507b8b..2ea9cf1a8d0 100644
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -43,7 +43,7 @@ static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
void dealloc_slot_struct(struct slot *slot)
{
kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot->name);
+ kfree(slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
}
@@ -63,11 +63,9 @@ struct slot *alloc_slot_struct(struct device_node *dn,
GFP_KERNEL);
if (!slot->hotplug_slot->info)
goto error_hpslot;
- slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
- if (!slot->hotplug_slot->name)
+ slot->name = kstrdup(drc_name, GFP_KERNEL);
+ if (!slot->name)
goto error_info;
- slot->name = slot->hotplug_slot->name;
- strcpy(slot->name, drc_name);
slot->dn = dn;
slot->index = drc_index;
slot->power_domain = power_domain;
@@ -137,7 +135,7 @@ int rpaphp_register_slot(struct slot *slot)
slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn);
else
slotno = -1;
- retval = pci_hp_register(php_slot, slot->bus, slotno);
+ retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name);
if (retval) {
err("pci_hp_register failed with error %d\n", retval);
return retval;
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index 410fe0394a8..3eee70928d4 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -161,7 +161,8 @@ static int sn_pci_bus_valid(struct pci_bus *pci_bus)
}
static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
- struct pci_bus *pci_bus, int device)
+ struct pci_bus *pci_bus, int device,
+ char *name)
{
struct pcibus_info *pcibus_info;
struct slot *slot;
@@ -173,15 +174,9 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
return -ENOMEM;
bss_hotplug_slot->private = slot;
- bss_hotplug_slot->name = kmalloc(SN_SLOT_NAME_SIZE, GFP_KERNEL);
- if (!bss_hotplug_slot->name) {
- kfree(bss_hotplug_slot->private);
- return -ENOMEM;
- }
-
slot->device_num = device;
slot->pci_bus = pci_bus;
- sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x",
+ sprintf(name, "%04x:%02x:%02x",
pci_domain_nr(pci_bus),
((u16)pcibus_info->pbi_buscommon.bs_persist_busnum),
device + 1);
@@ -418,7 +413,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
/*
* Add the slot's devices to the ACPI infrastructure */
if (SN_ACPI_BASE_SUPPORT() && ssdt) {
- unsigned long adr;
+ unsigned long long adr;
struct acpi_device *pdevice;
struct acpi_device *device;
acpi_handle phandle;
@@ -510,7 +505,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
/* free the ACPI resources for the slot */
if (SN_ACPI_BASE_SUPPORT() &&
PCI_CONTROLLER(slot->pci_bus)->acpi_handle) {
- unsigned long adr;
+ unsigned long long adr;
struct acpi_device *device;
acpi_handle phandle;
acpi_handle chandle = NULL;
@@ -608,7 +603,6 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot,
static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
{
kfree(bss_hotplug_slot->info);
- kfree(bss_hotplug_slot->name);
kfree(bss_hotplug_slot->private);
kfree(bss_hotplug_slot);
}
@@ -618,6 +612,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
int device;
struct pci_slot *pci_slot;
struct hotplug_slot *bss_hotplug_slot;
+ char name[SN_SLOT_NAME_SIZE];
int rc = 0;
/*
@@ -645,15 +640,14 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
}
if (sn_hp_slot_private_alloc(bss_hotplug_slot,
- pci_bus, device)) {
+ pci_bus, device, name)) {
rc = -ENOMEM;
goto alloc_err;
}
-
bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
bss_hotplug_slot->release = &sn_release_slot;
- rc = pci_hp_register(bss_hotplug_slot, pci_bus, device);
+ rc = pci_hp_register(bss_hotplug_slot, pci_bus, device, name);
if (rc)
goto register_err;
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 8a026f750de..4d9fed00e1d 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -69,15 +69,13 @@ struct slot {
u8 state;
u8 presence_save;
u8 pwr_save;
- struct timer_list task_event;
- u8 hp_slot;
struct controller *ctrl;
struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
struct list_head slot_list;
- char name[SLOT_NAME_SIZE];
struct delayed_work work; /* work for button event */
struct mutex lock;
+ u8 hp_slot;
};
struct event_info {
@@ -169,6 +167,11 @@ extern void cleanup_slots(struct controller *ctrl);
extern void shpchp_queue_pushbutton_work(struct work_struct *work);
extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
+static inline const char *slot_name(struct slot *slot)
+{
+ return hotplug_slot_name(slot->hotplug_slot);
+}
+
#ifdef CONFIG_ACPI
#include <linux/pci-acpi.h>
static inline int get_hp_params_from_firmware(struct pci_dev *dev,
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index cc38615395f..7af9191df4d 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -89,7 +89,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot);
@@ -101,8 +101,9 @@ static int init_slots(struct controller *ctrl)
struct slot *slot;
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *info;
+ char name[SLOT_NAME_SIZE];
int retval = -ENOMEM;
- int i, len, dup = 1;
+ int i;
for (i = 0; i < ctrl->num_slots; i++) {
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
@@ -119,8 +120,6 @@ static int init_slots(struct controller *ctrl)
goto error_hpslot;
hotplug_slot->info = info;
- hotplug_slot->name = slot->name;
-
slot->hp_slot = i;
slot->ctrl = ctrl;
slot->bus = ctrl->pci_dev->subordinate->number;
@@ -133,37 +132,24 @@ static int init_slots(struct controller *ctrl)
/* register this slot with the hotplug pci core */
hotplug_slot->private = slot;
hotplug_slot->release = &release_slot;
- snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number);
+ snprintf(name, SLOT_NAME_SIZE, "%d", slot->number);
hotplug_slot->ops = &shpchp_hotplug_slot_ops;
- get_power_status(hotplug_slot, &info->power_status);
- get_attention_status(hotplug_slot, &info->attention_status);
- get_latch_status(hotplug_slot, &info->latch_status);
- get_adapter_status(hotplug_slot, &info->adapter_status);
-
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
"slot_device_offset=%x\n", slot->bus, slot->device,
slot->hp_slot, slot->number, ctrl->slot_device_offset);
-duplicate_name:
retval = pci_hp_register(slot->hotplug_slot,
- ctrl->pci_dev->subordinate, slot->device);
+ ctrl->pci_dev->subordinate, slot->device, name);
if (retval) {
- /*
- * If slot N already exists, we'll try to create
- * slot N-1, N-2 ... N-M, until we overflow.
- */
- if (retval == -EEXIST) {
- len = snprintf(slot->name, SLOT_NAME_SIZE,
- "%d-%d", slot->number, dup++);
- if (len < SLOT_NAME_SIZE)
- goto duplicate_name;
- else
- err("duplicate slot name overflow\n");
- }
err("pci_hp_register failed with error %d\n", retval);
goto error_info;
}
+ get_power_status(hotplug_slot, &info->power_status);
+ get_attention_status(hotplug_slot, &info->attention_status);
+ get_latch_status(hotplug_slot, &info->latch_status);
+ get_adapter_status(hotplug_slot, &info->adapter_status);
+
list_add(&slot->slot_list, &ctrl->slot_list);
}
@@ -201,7 +187,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
{
struct slot *slot = get_slot(hotplug_slot);
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
hotplug_slot->info->attention_status = status;
slot->hpc_ops->set_attention_status(slot, status);
@@ -213,7 +199,7 @@ static int enable_slot (struct hotplug_slot *hotplug_slot)
{
struct slot *slot = get_slot(hotplug_slot);
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
return shpchp_sysfs_enable_slot(slot);
}
@@ -222,7 +208,7 @@ static int disable_slot (struct hotplug_slot *hotplug_slot)
{
struct slot *slot = get_slot(hotplug_slot);
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
return shpchp_sysfs_disable_slot(slot);
}
@@ -232,7 +218,7 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = get_slot(hotplug_slot);
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
retval = slot->hpc_ops->get_power_status(slot, value);
if (retval < 0)
@@ -246,7 +232,7 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = get_slot(hotplug_slot);
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
retval = slot->hpc_ops->get_attention_status(slot, value);
if (retval < 0)
@@ -260,7 +246,7 @@ static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = get_slot(hotplug_slot);
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
retval = slot->hpc_ops->get_latch_status(slot, value);
if (retval < 0)
@@ -274,7 +260,7 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
struct slot *slot = get_slot(hotplug_slot);
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
retval = slot->hpc_ops->get_adapter_status(slot, value);
if (retval < 0)
@@ -289,7 +275,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot,
struct slot *slot = get_slot(hotplug_slot);
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
retval = slot->hpc_ops->get_max_bus_speed(slot, value);
if (retval < 0)
@@ -303,7 +289,7 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
struct slot *slot = get_slot(hotplug_slot);
int retval;
- dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
+ dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
if (retval < 0)
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index dfb53932dfb..919b1ee4431 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -70,7 +70,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
/*
* Button pressed - See if need to TAKE ACTION!!!
*/
- info("Button pressed on Slot(%s)\n", p_slot->name);
+ info("Button pressed on Slot(%s)\n", slot_name(p_slot));
event_type = INT_BUTTON_PRESS;
queue_interrupt_event(p_slot, event_type);
@@ -98,7 +98,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
/*
* Switch opened
*/
- info("Latch open on Slot(%s)\n", p_slot->name);
+ info("Latch open on Slot(%s)\n", slot_name(p_slot));
event_type = INT_SWITCH_OPEN;
if (p_slot->pwr_save && p_slot->presence_save) {
event_type = INT_POWER_FAULT;
@@ -108,7 +108,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
/*
* Switch closed
*/
- info("Latch close on Slot(%s)\n", p_slot->name);
+ info("Latch close on Slot(%s)\n", slot_name(p_slot));
event_type = INT_SWITCH_CLOSE;
}
@@ -135,13 +135,13 @@ u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
/*
* Card Present
*/
- info("Card present on Slot(%s)\n", p_slot->name);
+ info("Card present on Slot(%s)\n", slot_name(p_slot));
event_type = INT_PRESENCE_ON;
} else {
/*
* Not Present
*/
- info("Card not present on Slot(%s)\n", p_slot->name);
+ info("Card not present on Slot(%s)\n", slot_name(p_slot));
event_type = INT_PRESENCE_OFF;
}
@@ -164,14 +164,14 @@ u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
/*
* Power fault Cleared
*/
- info("Power fault cleared on Slot(%s)\n", p_slot->name);
+ info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
p_slot->status = 0x00;
event_type = INT_POWER_FAULT_CLEAR;
} else {
/*
* Power fault
*/
- info("Power fault on Slot(%s)\n", p_slot->name);
+ info("Power fault on Slot(%s)\n", slot_name(p_slot));
event_type = INT_POWER_FAULT;
/* set power fault status for this board */
p_slot->status = 0xFF;
@@ -493,11 +493,11 @@ static void handle_button_press_event(struct slot *p_slot)
if (getstatus) {
p_slot->state = BLINKINGOFF_STATE;
info("PCI slot #%s - powering off due to button "
- "press.\n", p_slot->name);
+ "press.\n", slot_name(p_slot));
} else {
p_slot->state = BLINKINGON_STATE;
info("PCI slot #%s - powering on due to button "
- "press.\n", p_slot->name);
+ "press.\n", slot_name(p_slot));
}
/* blink green LED and turn off amber */
p_slot->hpc_ops->green_led_blink(p_slot);
@@ -512,7 +512,7 @@ static void handle_button_press_event(struct slot *p_slot)
* press the attention again before the 5 sec. limit
* expires to cancel hot-add or hot-remove
*/
- info("Button cancel on Slot(%s)\n", p_slot->name);
+ info("Button cancel on Slot(%s)\n", slot_name(p_slot));
dbg("%s: button cancel\n", __func__);
cancel_delayed_work(&p_slot->work);
if (p_slot->state == BLINKINGOFF_STATE)
@@ -521,7 +521,7 @@ static void handle_button_press_event(struct slot *p_slot)
p_slot->hpc_ops->green_led_off(p_slot);
p_slot->hpc_ops->set_attention_status(p_slot, 0);
info("PCI slot #%s - action canceled due to button press\n",
- p_slot->name);
+ slot_name(p_slot));
p_slot->state = STATIC_STATE;
break;
case POWEROFF_STATE:
@@ -531,7 +531,7 @@ static void handle_button_press_event(struct slot *p_slot)
* this means that the previous attention button action
* to hot-add or hot-remove is undergoing
*/
- info("Button ignore on Slot(%s)\n", p_slot->name);
+ info("Button ignore on Slot(%s)\n", slot_name(p_slot));
update_slot_info(p_slot);
break;
default:
@@ -574,17 +574,17 @@ static int shpchp_enable_slot (struct slot *p_slot)
mutex_lock(&p_slot->ctrl->crit_sect);
rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) {
- info("No adapter on slot(%s)\n", p_slot->name);
+ info("No adapter on slot(%s)\n", slot_name(p_slot));
goto out;
}
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
- info("Latch open on slot(%s)\n", p_slot->name);
+ info("Latch open on slot(%s)\n", slot_name(p_slot));
goto out;
}
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
- info("Already enabled on slot(%s)\n", p_slot->name);
+ info("Already enabled on slot(%s)\n", slot_name(p_slot));
goto out;
}
@@ -633,17 +633,17 @@ static int shpchp_disable_slot (struct slot *p_slot)
rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) {
- info("No adapter on slot(%s)\n", p_slot->name);
+ info("No adapter on slot(%s)\n", slot_name(p_slot));
goto out;
}
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
- info("Latch open on slot(%s)\n", p_slot->name);
+ info("Latch open on slot(%s)\n", slot_name(p_slot));
goto out;
}
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || !getstatus) {
- info("Already disabled slot(%s)\n", p_slot->name);
+ info("Already disabled slot(%s)\n", slot_name(p_slot));
goto out;
}
@@ -671,14 +671,14 @@ int shpchp_sysfs_enable_slot(struct slot *p_slot)
break;
case POWERON_STATE:
info("Slot %s is already in powering on state\n",
- p_slot->name);
+ slot_name(p_slot));
break;
case BLINKINGOFF_STATE:
case POWEROFF_STATE:
- info("Already enabled on slot %s\n", p_slot->name);
+ info("Already enabled on slot %s\n", slot_name(p_slot));
break;
default:
- err("Not a valid state on slot %s\n", p_slot->name);
+ err("Not a valid state on slot %s\n", slot_name(p_slot));
break;
}
mutex_unlock(&p_slot->lock);
@@ -703,14 +703,14 @@ int shpchp_sysfs_disable_slot(struct slot *p_slot)
break;
case POWEROFF_STATE:
info("Slot %s is already in powering off state\n",
- p_slot->name);
+ slot_name(p_slot));
break;
case BLINKINGON_STATE:
case POWERON_STATE:
- info("Already disabled on slot %s\n", p_slot->name);
+ info("Already disabled on slot %s\n", slot_name(p_slot));
break;
default:
- err("Not a valid state on slot %s\n", p_slot->name);
+ err("Not a valid state on slot %s\n", slot_name(p_slot));
break;
}
mutex_unlock(&p_slot->lock);
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
index 279c940a003..bf7d6ce9bbb 100644
--- a/drivers/pci/htirq.c
+++ b/drivers/pci/htirq.c
@@ -126,7 +126,8 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
cfg->msg.address_hi = 0xffffffff;
irq = create_irq();
- if (irq < 0) {
+
+ if (irq <= 0) {
kfree(cfg);
return -EBUSY;
}
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index fc5f2dbf532..a2692724b68 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -18,6 +18,7 @@
* Author: Ashok Raj <ashok.raj@intel.com>
* Author: Shaohua Li <shaohua.li@intel.com>
* Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * Author: Fenghua Yu <fenghua.yu@intel.com>
*/
#include <linux/init.h>
@@ -35,11 +36,13 @@
#include <linux/timer.h>
#include <linux/iova.h>
#include <linux/intel-iommu.h>
-#include <asm/proto.h> /* force_iommu in this header in x86-64*/
#include <asm/cacheflush.h>
#include <asm/iommu.h>
#include "pci.h"
+#define ROOT_SIZE VTD_PAGE_SIZE
+#define CONTEXT_SIZE VTD_PAGE_SIZE
+
#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
@@ -199,7 +202,7 @@ static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
spin_unlock_irqrestore(&iommu->lock, flags);
return NULL;
}
- __iommu_flush_cache(iommu, (void *)context, PAGE_SIZE_4K);
+ __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
phy_addr = virt_to_phys((void *)context);
set_root_value(root, phy_addr);
set_root_present(root);
@@ -345,7 +348,7 @@ static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
return NULL;
}
__iommu_flush_cache(domain->iommu, tmp_page,
- PAGE_SIZE_4K);
+ PAGE_SIZE);
dma_set_pte_addr(*pte, virt_to_phys(tmp_page));
/*
* high level table always sets r/w, last level page
@@ -408,13 +411,13 @@ static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
start &= (((u64)1) << addr_width) - 1;
end &= (((u64)1) << addr_width) - 1;
/* in case it's partial page */
- start = PAGE_ALIGN_4K(start);
- end &= PAGE_MASK_4K;
+ start = PAGE_ALIGN(start);
+ end &= PAGE_MASK;
/* we don't need lock here, nobody else touches the iova range */
while (start < end) {
dma_pte_clear_one(domain, start);
- start += PAGE_SIZE_4K;
+ start += VTD_PAGE_SIZE;
}
}
@@ -468,7 +471,7 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu)
if (!root)
return -ENOMEM;
- __iommu_flush_cache(iommu, root, PAGE_SIZE_4K);
+ __iommu_flush_cache(iommu, root, ROOT_SIZE);
spin_lock_irqsave(&iommu->lock, flags);
iommu->root_entry = root;
@@ -563,31 +566,10 @@ static int __iommu_flush_context(struct intel_iommu *iommu,
spin_unlock_irqrestore(&iommu->register_lock, flag);
- /* flush context entry will implictly flush write buffer */
+ /* flush context entry will implicitly flush write buffer */
return 0;
}
-static int inline iommu_flush_context_global(struct intel_iommu *iommu,
- int non_present_entry_flush)
-{
- return __iommu_flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL,
- non_present_entry_flush);
-}
-
-static int inline iommu_flush_context_domain(struct intel_iommu *iommu, u16 did,
- int non_present_entry_flush)
-{
- return __iommu_flush_context(iommu, did, 0, 0, DMA_CCMD_DOMAIN_INVL,
- non_present_entry_flush);
-}
-
-static int inline iommu_flush_context_device(struct intel_iommu *iommu,
- u16 did, u16 source_id, u8 function_mask, int non_present_entry_flush)
-{
- return __iommu_flush_context(iommu, did, source_id, function_mask,
- DMA_CCMD_DEVICE_INVL, non_present_entry_flush);
-}
-
/* return value determine if we need a write buffer flush */
static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
u64 addr, unsigned int size_order, u64 type,
@@ -655,37 +637,25 @@ static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
- DMA_TLB_IIRG(type), DMA_TLB_IAIG(val));
- /* flush context entry will implictly flush write buffer */
+ (unsigned long long)DMA_TLB_IIRG(type),
+ (unsigned long long)DMA_TLB_IAIG(val));
+ /* flush iotlb entry will implicitly flush write buffer */
return 0;
}
-static int inline iommu_flush_iotlb_global(struct intel_iommu *iommu,
- int non_present_entry_flush)
-{
- return __iommu_flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
- non_present_entry_flush);
-}
-
-static int inline iommu_flush_iotlb_dsi(struct intel_iommu *iommu, u16 did,
- int non_present_entry_flush)
-{
- return __iommu_flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH,
- non_present_entry_flush);
-}
-
static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
u64 addr, unsigned int pages, int non_present_entry_flush)
{
unsigned int mask;
- BUG_ON(addr & (~PAGE_MASK_4K));
+ BUG_ON(addr & (~VTD_PAGE_MASK));
BUG_ON(pages == 0);
/* Fallback to domain selective flush if no PSI support */
if (!cap_pgsel_inv(iommu->cap))
- return iommu_flush_iotlb_dsi(iommu, did,
- non_present_entry_flush);
+ return iommu->flush.flush_iotlb(iommu, did, 0, 0,
+ DMA_TLB_DSI_FLUSH,
+ non_present_entry_flush);
/*
* PSI requires page size to be 2 ^ x, and the base address is naturally
@@ -694,11 +664,12 @@ static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
mask = ilog2(__roundup_pow_of_two(pages));
/* Fallback to domain selective flush if size is too big */
if (mask > cap_max_amask_val(iommu->cap))
- return iommu_flush_iotlb_dsi(iommu, did,
- non_present_entry_flush);
+ return iommu->flush.flush_iotlb(iommu, did, 0, 0,
+ DMA_TLB_DSI_FLUSH, non_present_entry_flush);
- return __iommu_flush_iotlb(iommu, did, addr, mask,
- DMA_TLB_PSI_FLUSH, non_present_entry_flush);
+ return iommu->flush.flush_iotlb(iommu, did, addr, mask,
+ DMA_TLB_PSI_FLUSH,
+ non_present_entry_flush);
}
static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
@@ -831,7 +802,7 @@ void dmar_msi_read(int irq, struct msi_msg *msg)
}
static int iommu_page_fault_do_one(struct intel_iommu *iommu, int type,
- u8 fault_reason, u16 source_id, u64 addr)
+ u8 fault_reason, u16 source_id, unsigned long long addr)
{
const char *reason;
@@ -1084,9 +1055,9 @@ static void dmar_init_reserved_ranges(void)
if (!r->flags || !(r->flags & IORESOURCE_MEM))
continue;
addr = r->start;
- addr &= PAGE_MASK_4K;
+ addr &= PAGE_MASK;
size = r->end - addr;
- size = PAGE_ALIGN_4K(size);
+ size = PAGE_ALIGN(size);
iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
IOVA_PFN(size + addr) - 1);
if (!iova)
@@ -1148,7 +1119,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
domain->pgd = (struct dma_pte *)alloc_pgtable_page();
if (!domain->pgd)
return -ENOMEM;
- __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE_4K);
+ __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
return 0;
}
@@ -1164,7 +1135,7 @@ static void domain_exit(struct dmar_domain *domain)
/* destroy iovas */
put_iova_domain(&domain->iovad);
end = DOMAIN_MAX_ADDR(domain->gaw);
- end = end & (~PAGE_MASK_4K);
+ end = end & (~PAGE_MASK);
/* clear ptes */
dma_pte_clear_range(domain, 0, end);
@@ -1204,11 +1175,13 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
__iommu_flush_cache(iommu, context, sizeof(*context));
/* it's a non-present to present mapping */
- if (iommu_flush_context_device(iommu, domain->id,
- (((u16)bus) << 8) | devfn, DMA_CCMD_MASK_NOBIT, 1))
+ if (iommu->flush.flush_context(iommu, domain->id,
+ (((u16)bus) << 8) | devfn, DMA_CCMD_MASK_NOBIT,
+ DMA_CCMD_DEVICE_INVL, 1))
iommu_flush_write_buffer(iommu);
else
- iommu_flush_iotlb_dsi(iommu, 0, 0);
+ iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH, 0);
+
spin_unlock_irqrestore(&iommu->lock, flags);
return 0;
}
@@ -1283,22 +1256,25 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
u64 start_pfn, end_pfn;
struct dma_pte *pte;
int index;
+ int addr_width = agaw_to_width(domain->agaw);
+
+ hpa &= (((u64)1) << addr_width) - 1;
if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
return -EINVAL;
- iova &= PAGE_MASK_4K;
- start_pfn = ((u64)hpa) >> PAGE_SHIFT_4K;
- end_pfn = (PAGE_ALIGN_4K(((u64)hpa) + size)) >> PAGE_SHIFT_4K;
+ iova &= PAGE_MASK;
+ start_pfn = ((u64)hpa) >> VTD_PAGE_SHIFT;
+ end_pfn = (VTD_PAGE_ALIGN(((u64)hpa) + size)) >> VTD_PAGE_SHIFT;
index = 0;
while (start_pfn < end_pfn) {
- pte = addr_to_dma_pte(domain, iova + PAGE_SIZE_4K * index);
+ pte = addr_to_dma_pte(domain, iova + VTD_PAGE_SIZE * index);
if (!pte)
return -ENOMEM;
/* We don't need lock here, nobody else
* touches the iova range
*/
BUG_ON(dma_pte_addr(*pte));
- dma_set_pte_addr(*pte, start_pfn << PAGE_SHIFT_4K);
+ dma_set_pte_addr(*pte, start_pfn << VTD_PAGE_SHIFT);
dma_set_pte_prot(*pte, prot);
__iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
start_pfn++;
@@ -1310,8 +1286,10 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
static void detach_domain_for_dev(struct dmar_domain *domain, u8 bus, u8 devfn)
{
clear_context_table(domain->iommu, bus, devfn);
- iommu_flush_context_global(domain->iommu, 0);
- iommu_flush_iotlb_global(domain->iommu, 0);
+ domain->iommu->flush.flush_context(domain->iommu, 0, 0, 0,
+ DMA_CCMD_GLOBAL_INVL, 0);
+ domain->iommu->flush.flush_iotlb(domain->iommu, 0, 0, 0,
+ DMA_TLB_GLOBAL_FLUSH, 0);
}
static void domain_remove_dev_info(struct dmar_domain *domain)
@@ -1474,11 +1452,13 @@ error:
return find_domain(pdev);
}
-static int iommu_prepare_identity_map(struct pci_dev *pdev, u64 start, u64 end)
+static int iommu_prepare_identity_map(struct pci_dev *pdev,
+ unsigned long long start,
+ unsigned long long end)
{
struct dmar_domain *domain;
unsigned long size;
- u64 base;
+ unsigned long long base;
int ret;
printk(KERN_INFO
@@ -1490,9 +1470,9 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, u64 start, u64 end)
return -ENOMEM;
/* The address might not be aligned */
- base = start & PAGE_MASK_4K;
+ base = start & PAGE_MASK;
size = end - base;
- size = PAGE_ALIGN_4K(size);
+ size = PAGE_ALIGN(size);
if (!reserve_iova(&domain->iovad, IOVA_PFN(base),
IOVA_PFN(base + size) - 1)) {
printk(KERN_ERR "IOMMU: reserve iova failed\n");
@@ -1662,6 +1642,28 @@ int __init init_dmars(void)
}
}
+ for_each_drhd_unit(drhd) {
+ if (drhd->ignored)
+ continue;
+
+ iommu = drhd->iommu;
+ if (dmar_enable_qi(iommu)) {
+ /*
+ * Queued Invalidate not enabled, use Register Based
+ * Invalidate
+ */
+ iommu->flush.flush_context = __iommu_flush_context;
+ iommu->flush.flush_iotlb = __iommu_flush_iotlb;
+ printk(KERN_INFO "IOMMU 0x%Lx: using Register based "
+ "invalidation\n", drhd->reg_base_addr);
+ } else {
+ iommu->flush.flush_context = qi_flush_context;
+ iommu->flush.flush_iotlb = qi_flush_iotlb;
+ printk(KERN_INFO "IOMMU 0x%Lx: using Queued "
+ "invalidation\n", drhd->reg_base_addr);
+ }
+ }
+
/*
* For each rmrr
* for each dev attached to rmrr
@@ -1714,9 +1716,10 @@ int __init init_dmars(void)
iommu_set_root_entry(iommu);
- iommu_flush_context_global(iommu, 0);
- iommu_flush_iotlb_global(iommu, 0);
-
+ iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL,
+ 0);
+ iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
+ 0);
iommu_disable_protect_mem_regions(iommu);
ret = iommu_enable_translation(iommu);
@@ -1738,8 +1741,8 @@ error:
static inline u64 aligned_size(u64 host_addr, size_t size)
{
u64 addr;
- addr = (host_addr & (~PAGE_MASK_4K)) + size;
- return PAGE_ALIGN_4K(addr);
+ addr = (host_addr & (~PAGE_MASK)) + size;
+ return PAGE_ALIGN(addr);
}
struct iova *
@@ -1753,20 +1756,20 @@ iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
return NULL;
piova = alloc_iova(&domain->iovad,
- size >> PAGE_SHIFT_4K, IOVA_PFN(end), 1);
+ size >> PAGE_SHIFT, IOVA_PFN(end), 1);
return piova;
}
static struct iova *
__intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
- size_t size)
+ size_t size, u64 dma_mask)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct iova *iova = NULL;
- if ((pdev->dma_mask <= DMA_32BIT_MASK) || (dmar_forcedac)) {
- iova = iommu_alloc_iova(domain, size, pdev->dma_mask);
- } else {
+ if (dma_mask <= DMA_32BIT_MASK || dmar_forcedac)
+ iova = iommu_alloc_iova(domain, size, dma_mask);
+ else {
/*
* First try to allocate an io virtual address in
* DMA_32BIT_MASK and if that fails then try allocating
@@ -1774,7 +1777,7 @@ __intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
*/
iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK);
if (!iova)
- iova = iommu_alloc_iova(domain, size, pdev->dma_mask);
+ iova = iommu_alloc_iova(domain, size, dma_mask);
}
if (!iova) {
@@ -1813,12 +1816,12 @@ get_valid_domain_for_dev(struct pci_dev *pdev)
return domain;
}
-static dma_addr_t
-intel_map_single(struct device *hwdev, phys_addr_t paddr, size_t size, int dir)
+static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
+ size_t size, int dir, u64 dma_mask)
{
struct pci_dev *pdev = to_pci_dev(hwdev);
struct dmar_domain *domain;
- unsigned long start_paddr;
+ phys_addr_t start_paddr;
struct iova *iova;
int prot = 0;
int ret;
@@ -1833,11 +1836,11 @@ intel_map_single(struct device *hwdev, phys_addr_t paddr, size_t size, int dir)
size = aligned_size((u64)paddr, size);
- iova = __intel_alloc_iova(hwdev, domain, size);
+ iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
if (!iova)
goto error;
- start_paddr = iova->pfn_lo << PAGE_SHIFT_4K;
+ start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
/*
* Check if DMAR supports zero-length reads on write only
@@ -1855,30 +1858,33 @@ intel_map_single(struct device *hwdev, phys_addr_t paddr, size_t size, int dir)
* is not a big problem
*/
ret = domain_page_mapping(domain, start_paddr,
- ((u64)paddr) & PAGE_MASK_4K, size, prot);
+ ((u64)paddr) & PAGE_MASK, size, prot);
if (ret)
goto error;
- pr_debug("Device %s request: %lx@%llx mapping: %lx@%llx, dir %d\n",
- pci_name(pdev), size, (u64)paddr,
- size, (u64)start_paddr, dir);
-
/* it's a non-present to present mapping */
ret = iommu_flush_iotlb_psi(domain->iommu, domain->id,
- start_paddr, size >> PAGE_SHIFT_4K, 1);
+ start_paddr, size >> VTD_PAGE_SHIFT, 1);
if (ret)
iommu_flush_write_buffer(domain->iommu);
- return (start_paddr + ((u64)paddr & (~PAGE_MASK_4K)));
+ return start_paddr + ((u64)paddr & (~PAGE_MASK));
error:
if (iova)
__free_iova(&domain->iovad, iova);
printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n",
- pci_name(pdev), size, (u64)paddr, dir);
+ pci_name(pdev), size, (unsigned long long)paddr, dir);
return 0;
}
+dma_addr_t intel_map_single(struct device *hwdev, phys_addr_t paddr,
+ size_t size, int dir)
+{
+ return __intel_map_single(hwdev, paddr, size, dir,
+ to_pci_dev(hwdev)->dma_mask);
+}
+
static void flush_unmaps(void)
{
int i, j;
@@ -1891,7 +1897,8 @@ static void flush_unmaps(void)
struct intel_iommu *iommu =
deferred_flush[i].domain[0]->iommu;
- iommu_flush_iotlb_global(iommu, 0);
+ iommu->flush.flush_iotlb(iommu, 0, 0, 0,
+ DMA_TLB_GLOBAL_FLUSH, 0);
for (j = 0; j < deferred_flush[i].next; j++) {
__free_iova(&deferred_flush[i].domain[j]->iovad,
deferred_flush[i].iova[j]);
@@ -1936,8 +1943,8 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova)
spin_unlock_irqrestore(&async_umap_flush_lock, flags);
}
-static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
- size_t size, int dir)
+void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
+ int dir)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct dmar_domain *domain;
@@ -1953,11 +1960,11 @@ static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
if (!iova)
return;
- start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+ start_addr = iova->pfn_lo << PAGE_SHIFT;
size = aligned_size((u64)dev_addr, size);
pr_debug("Device %s unmapping: %lx@%llx\n",
- pci_name(pdev), size, (u64)start_addr);
+ pci_name(pdev), size, (unsigned long long)start_addr);
/* clear the whole page */
dma_pte_clear_range(domain, start_addr, start_addr + size);
@@ -1965,7 +1972,7 @@ static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
dma_pte_free_pagetable(domain, start_addr, start_addr + size);
if (intel_iommu_strict) {
if (iommu_flush_iotlb_psi(domain->iommu,
- domain->id, start_addr, size >> PAGE_SHIFT_4K, 0))
+ domain->id, start_addr, size >> VTD_PAGE_SHIFT, 0))
iommu_flush_write_buffer(domain->iommu);
/* free iova */
__free_iova(&domain->iovad, iova);
@@ -1978,13 +1985,13 @@ static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
}
}
-static void * intel_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags)
+void *intel_alloc_coherent(struct device *hwdev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flags)
{
void *vaddr;
int order;
- size = PAGE_ALIGN_4K(size);
+ size = PAGE_ALIGN(size);
order = get_order(size);
flags &= ~(GFP_DMA | GFP_DMA32);
@@ -1993,19 +2000,21 @@ static void * intel_alloc_coherent(struct device *hwdev, size_t size,
return NULL;
memset(vaddr, 0, size);
- *dma_handle = intel_map_single(hwdev, virt_to_bus(vaddr), size, DMA_BIDIRECTIONAL);
+ *dma_handle = __intel_map_single(hwdev, virt_to_bus(vaddr), size,
+ DMA_BIDIRECTIONAL,
+ hwdev->coherent_dma_mask);
if (*dma_handle)
return vaddr;
free_pages((unsigned long)vaddr, order);
return NULL;
}
-static void intel_free_coherent(struct device *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
{
int order;
- size = PAGE_ALIGN_4K(size);
+ size = PAGE_ALIGN(size);
order = get_order(size);
intel_unmap_single(hwdev, dma_handle, size, DMA_BIDIRECTIONAL);
@@ -2013,8 +2022,9 @@ static void intel_free_coherent(struct device *hwdev, size_t size,
}
#define SG_ENT_VIRT_ADDRESS(sg) (sg_virt((sg)))
-static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
- int nelems, int dir)
+
+void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
+ int nelems, int dir)
{
int i;
struct pci_dev *pdev = to_pci_dev(hwdev);
@@ -2038,7 +2048,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
size += aligned_size((u64)addr, sg->length);
}
- start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+ start_addr = iova->pfn_lo << PAGE_SHIFT;
/* clear the whole page */
dma_pte_clear_range(domain, start_addr, start_addr + size);
@@ -2046,7 +2056,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
dma_pte_free_pagetable(domain, start_addr, start_addr + size);
if (iommu_flush_iotlb_psi(domain->iommu, domain->id, start_addr,
- size >> PAGE_SHIFT_4K, 0))
+ size >> VTD_PAGE_SHIFT, 0))
iommu_flush_write_buffer(domain->iommu);
/* free iova */
@@ -2067,8 +2077,8 @@ static int intel_nontranslate_map_sg(struct device *hddev,
return nelems;
}
-static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist,
- int nelems, int dir)
+int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
+ int dir)
{
void *addr;
int i;
@@ -2096,7 +2106,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist,
size += aligned_size((u64)addr, sg->length);
}
- iova = __intel_alloc_iova(hwdev, domain, size);
+ iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
if (!iova) {
sglist->dma_length = 0;
return 0;
@@ -2112,14 +2122,14 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist,
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
prot |= DMA_PTE_WRITE;
- start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+ start_addr = iova->pfn_lo << PAGE_SHIFT;
offset = 0;
for_each_sg(sglist, sg, nelems, i) {
addr = SG_ENT_VIRT_ADDRESS(sg);
addr = (void *)virt_to_phys(addr);
size = aligned_size((u64)addr, sg->length);
ret = domain_page_mapping(domain, start_addr + offset,
- ((u64)addr) & PAGE_MASK_4K,
+ ((u64)addr) & PAGE_MASK,
size, prot);
if (ret) {
/* clear the page */
@@ -2133,14 +2143,14 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist,
return 0;
}
sg->dma_address = start_addr + offset +
- ((u64)addr & (~PAGE_MASK_4K));
+ ((u64)addr & (~PAGE_MASK));
sg->dma_length = sg->length;
offset += size;
}
/* it's a non-present to present mapping */
if (iommu_flush_iotlb_psi(domain->iommu, domain->id,
- start_addr, offset >> PAGE_SHIFT_4K, 1))
+ start_addr, offset >> VTD_PAGE_SHIFT, 1))
iommu_flush_write_buffer(domain->iommu);
return nelems;
}
@@ -2180,7 +2190,6 @@ static inline int iommu_devinfo_cache_init(void)
sizeof(struct device_domain_info),
0,
SLAB_HWCACHE_ALIGN,
-
NULL);
if (!iommu_devinfo_cache) {
printk(KERN_ERR "Couldn't create devinfo cache\n");
@@ -2198,7 +2207,6 @@ static inline int iommu_iova_cache_init(void)
sizeof(struct iova),
0,
SLAB_HWCACHE_ALIGN,
-
NULL);
if (!iommu_iova_cache) {
printk(KERN_ERR "Couldn't create iova cache\n");
@@ -2327,7 +2335,7 @@ void intel_iommu_domain_exit(struct dmar_domain *domain)
return;
end = DOMAIN_MAX_ADDR(domain->gaw);
- end = end & (~PAGE_MASK_4K);
+ end = end & (~VTD_PAGE_MASK);
/* clear ptes */
dma_pte_clear_range(domain, 0, end);
@@ -2423,6 +2431,6 @@ u64 intel_iommu_iova_to_pfn(struct dmar_domain *domain, u64 iova)
if (pte)
pfn = dma_pte_addr(*pte);
- return pfn >> PAGE_SHIFT_4K;
+ return pfn >> VTD_PAGE_SHIFT;
}
EXPORT_SYMBOL_GPL(intel_iommu_iova_to_pfn);
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index 738d4c89581..2de5a3238c9 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -1,3 +1,4 @@
+#include <linux/interrupt.h>
#include <linux/dmar.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
@@ -11,41 +12,64 @@ static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
static int ir_ioapic_num;
int intr_remapping_enabled;
-static struct {
+struct irq_2_iommu {
struct intel_iommu *iommu;
u16 irte_index;
u16 sub_handle;
u8 irte_mask;
-} irq_2_iommu[NR_IRQS];
+};
+
+static struct irq_2_iommu irq_2_iommuX[NR_IRQS];
+
+static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
+{
+ return (irq < nr_irqs) ? irq_2_iommuX + irq : NULL;
+}
+
+static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
+{
+ return irq_2_iommu(irq);
+}
static DEFINE_SPINLOCK(irq_2_ir_lock);
-int irq_remapped(int irq)
+static struct irq_2_iommu *valid_irq_2_iommu(unsigned int irq)
{
- if (irq > NR_IRQS)
- return 0;
+ struct irq_2_iommu *irq_iommu;
+
+ irq_iommu = irq_2_iommu(irq);
+
+ if (!irq_iommu)
+ return NULL;
+
+ if (!irq_iommu->iommu)
+ return NULL;
- if (!irq_2_iommu[irq].iommu)
- return 0;
+ return irq_iommu;
+}
- return 1;
+int irq_remapped(int irq)
+{
+ return valid_irq_2_iommu(irq) != NULL;
}
int get_irte(int irq, struct irte *entry)
{
int index;
+ struct irq_2_iommu *irq_iommu;
- if (!entry || irq > NR_IRQS)
+ if (!entry)
return -1;
spin_lock(&irq_2_ir_lock);
- if (!irq_2_iommu[irq].iommu) {
+ irq_iommu = valid_irq_2_iommu(irq);
+ if (!irq_iommu) {
spin_unlock(&irq_2_ir_lock);
return -1;
}
- index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
- *entry = *(irq_2_iommu[irq].iommu->ir_table->base + index);
+ index = irq_iommu->irte_index + irq_iommu->sub_handle;
+ *entry = *(irq_iommu->iommu->ir_table->base + index);
spin_unlock(&irq_2_ir_lock);
return 0;
@@ -54,6 +78,7 @@ int get_irte(int irq, struct irte *entry)
int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
{
struct ir_table *table = iommu->ir_table;
+ struct irq_2_iommu *irq_iommu;
u16 index, start_index;
unsigned int mask = 0;
int i;
@@ -61,6 +86,10 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
if (!count)
return -1;
+ /* protect irq_2_iommu_alloc later */
+ if (irq >= nr_irqs)
+ return -1;
+
/*
* start the IRTE search from index 0.
*/
@@ -100,10 +129,11 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
for (i = index; i < index + count; i++)
table->base[i].present = 1;
- irq_2_iommu[irq].iommu = iommu;
- irq_2_iommu[irq].irte_index = index;
- irq_2_iommu[irq].sub_handle = 0;
- irq_2_iommu[irq].irte_mask = mask;
+ irq_iommu = irq_2_iommu_alloc(irq);
+ irq_iommu->iommu = iommu;
+ irq_iommu->irte_index = index;
+ irq_iommu->sub_handle = 0;
+ irq_iommu->irte_mask = mask;
spin_unlock(&irq_2_ir_lock);
@@ -124,31 +154,33 @@ static void qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
int map_irq_to_irte_handle(int irq, u16 *sub_handle)
{
int index;
+ struct irq_2_iommu *irq_iommu;
spin_lock(&irq_2_ir_lock);
- if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+ irq_iommu = valid_irq_2_iommu(irq);
+ if (!irq_iommu) {
spin_unlock(&irq_2_ir_lock);
return -1;
}
- *sub_handle = irq_2_iommu[irq].sub_handle;
- index = irq_2_iommu[irq].irte_index;
+ *sub_handle = irq_iommu->sub_handle;
+ index = irq_iommu->irte_index;
spin_unlock(&irq_2_ir_lock);
return index;
}
int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
{
+ struct irq_2_iommu *irq_iommu;
+
spin_lock(&irq_2_ir_lock);
- if (irq >= NR_IRQS || irq_2_iommu[irq].iommu) {
- spin_unlock(&irq_2_ir_lock);
- return -1;
- }
- irq_2_iommu[irq].iommu = iommu;
- irq_2_iommu[irq].irte_index = index;
- irq_2_iommu[irq].sub_handle = subhandle;
- irq_2_iommu[irq].irte_mask = 0;
+ irq_iommu = irq_2_iommu_alloc(irq);
+
+ irq_iommu->iommu = iommu;
+ irq_iommu->irte_index = index;
+ irq_iommu->sub_handle = subhandle;
+ irq_iommu->irte_mask = 0;
spin_unlock(&irq_2_ir_lock);
@@ -157,16 +189,19 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index)
{
+ struct irq_2_iommu *irq_iommu;
+
spin_lock(&irq_2_ir_lock);
- if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+ irq_iommu = valid_irq_2_iommu(irq);
+ if (!irq_iommu) {
spin_unlock(&irq_2_ir_lock);
return -1;
}
- irq_2_iommu[irq].iommu = NULL;
- irq_2_iommu[irq].irte_index = 0;
- irq_2_iommu[irq].sub_handle = 0;
- irq_2_iommu[irq].irte_mask = 0;
+ irq_iommu->iommu = NULL;
+ irq_iommu->irte_index = 0;
+ irq_iommu->sub_handle = 0;
+ irq_2_iommu(irq)->irte_mask = 0;
spin_unlock(&irq_2_ir_lock);
@@ -178,16 +213,18 @@ int modify_irte(int irq, struct irte *irte_modified)
int index;
struct irte *irte;
struct intel_iommu *iommu;
+ struct irq_2_iommu *irq_iommu;
spin_lock(&irq_2_ir_lock);
- if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+ irq_iommu = valid_irq_2_iommu(irq);
+ if (!irq_iommu) {
spin_unlock(&irq_2_ir_lock);
return -1;
}
- iommu = irq_2_iommu[irq].iommu;
+ iommu = irq_iommu->iommu;
- index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+ index = irq_iommu->irte_index + irq_iommu->sub_handle;
irte = &iommu->ir_table->base[index];
set_64bit((unsigned long *)irte, irte_modified->low | (1 << 1));
@@ -203,18 +240,20 @@ int flush_irte(int irq)
{
int index;
struct intel_iommu *iommu;
+ struct irq_2_iommu *irq_iommu;
spin_lock(&irq_2_ir_lock);
- if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+ irq_iommu = valid_irq_2_iommu(irq);
+ if (!irq_iommu) {
spin_unlock(&irq_2_ir_lock);
return -1;
}
- iommu = irq_2_iommu[irq].iommu;
+ iommu = irq_iommu->iommu;
- index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+ index = irq_iommu->irte_index + irq_iommu->sub_handle;
- qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask);
+ qi_flush_iec(iommu, index, irq_iommu->irte_mask);
spin_unlock(&irq_2_ir_lock);
return 0;
@@ -246,28 +285,30 @@ int free_irte(int irq)
int index, i;
struct irte *irte;
struct intel_iommu *iommu;
+ struct irq_2_iommu *irq_iommu;
spin_lock(&irq_2_ir_lock);
- if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+ irq_iommu = valid_irq_2_iommu(irq);
+ if (!irq_iommu) {
spin_unlock(&irq_2_ir_lock);
return -1;
}
- iommu = irq_2_iommu[irq].iommu;
+ iommu = irq_iommu->iommu;
- index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+ index = irq_iommu->irte_index + irq_iommu->sub_handle;
irte = &iommu->ir_table->base[index];
- if (!irq_2_iommu[irq].sub_handle) {
- for (i = 0; i < (1 << irq_2_iommu[irq].irte_mask); i++)
+ if (!irq_iommu->sub_handle) {
+ for (i = 0; i < (1 << irq_iommu->irte_mask); i++)
set_64bit((unsigned long *)irte, 0);
- qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask);
+ qi_flush_iec(iommu, index, irq_iommu->irte_mask);
}
- irq_2_iommu[irq].iommu = NULL;
- irq_2_iommu[irq].irte_index = 0;
- irq_2_iommu[irq].sub_handle = 0;
- irq_2_iommu[irq].irte_mask = 0;
+ irq_iommu->iommu = NULL;
+ irq_iommu->irte_index = 0;
+ irq_iommu->sub_handle = 0;
+ irq_iommu->irte_mask = 0;
spin_unlock(&irq_2_ir_lock);
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 4a10b5624f7..74801f7df9c 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -378,23 +378,21 @@ static int msi_capability_init(struct pci_dev *dev)
entry->msi_attrib.masked = 1;
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
entry->msi_attrib.pos = pos;
- if (is_mask_bit_support(control)) {
+ if (entry->msi_attrib.maskbit) {
entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
- is_64bit_address(control));
+ entry->msi_attrib.is_64);
}
entry->dev = dev;
if (entry->msi_attrib.maskbit) {
unsigned int maskbits, temp;
/* All MSIs are unmasked by default, Mask them all */
pci_read_config_dword(dev,
- msi_mask_bits_reg(pos, is_64bit_address(control)),
+ msi_mask_bits_reg(pos, entry->msi_attrib.is_64),
&maskbits);
temp = (1 << multi_msi_capable(control));
temp = ((temp - 1) & ~temp);
maskbits |= temp;
- pci_write_config_dword(dev,
- msi_mask_bits_reg(pos, is_64bit_address(control)),
- maskbits);
+ pci_write_config_dword(dev, entry->msi_attrib.is_64, maskbits);
entry->msi_attrib.maskbits_mask = temp;
}
list_add_tail(&entry->list, &dev->msi_list);
@@ -761,3 +759,24 @@ 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)
+{
+ if (acpi_pci_disabled)
+ return;
+ pci_osc_support_set(OSC_MSI_SUPPORT);
+ pcie_osc_support_set(OSC_MSI_SUPPORT);
+}
+#else
+static inline void msi_acpi_init(void) { }
+#endif /* CONFIG_ACPI */
+
+void __devinit msi_init(void)
+{
+ if (!pci_msi_enable)
+ return;
+ msi_acpi_init();
+}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 89a2f0fa10f..dfe7c8e1b18 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -24,17 +24,17 @@ struct acpi_osc_data {
acpi_handle handle;
u32 support_set;
u32 control_set;
- int is_queried;
- u32 query_result;
struct list_head sibiling;
};
static LIST_HEAD(acpi_osc_data_list);
struct acpi_osc_args {
u32 capbuf[3];
- u32 query_result;
+ u32 ctrl_result;
};
+static DEFINE_MUTEX(pci_acpi_lock);
+
static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle)
{
struct acpi_osc_data *data;
@@ -108,9 +108,8 @@ static acpi_status acpi_run_osc(acpi_handle handle,
goto out_kfree;
}
out_success:
- if (flags & OSC_QUERY_ENABLE)
- osc_args->query_result =
- *((u32 *)(out_obj->buffer.pointer + 8));
+ osc_args->ctrl_result =
+ *((u32 *)(out_obj->buffer.pointer + 8));
status = AE_OK;
out_kfree:
@@ -118,41 +117,53 @@ out_kfree:
return status;
}
-static acpi_status acpi_query_osc(acpi_handle handle,
- u32 level, void *context, void **retval)
+static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data,
+ u32 *result)
{
acpi_status status;
- struct acpi_osc_data *osc_data;
- u32 flags = (unsigned long)context, support_set;
- acpi_handle tmp;
+ u32 support_set;
struct acpi_osc_args osc_args;
- status = acpi_get_handle(handle, "_OSC", &tmp);
- if (ACPI_FAILURE(status))
- return status;
-
- osc_data = acpi_get_osc_data(handle);
- if (!osc_data) {
- printk(KERN_ERR "acpi osc data array is full\n");
- return AE_ERROR;
- }
-
/* do _OSC query for all possible controls */
support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS);
osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set;
osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
- status = acpi_run_osc(handle, &osc_args);
+ status = acpi_run_osc(osc_data->handle, &osc_args);
if (ACPI_SUCCESS(status)) {
osc_data->support_set = support_set;
- osc_data->query_result = osc_args.query_result;
- osc_data->is_queried = 1;
+ *result = osc_args.ctrl_result;
}
return status;
}
+static acpi_status acpi_query_osc(acpi_handle handle,
+ u32 level, void *context, void **retval)
+{
+ acpi_status status;
+ struct acpi_osc_data *osc_data;
+ u32 flags = (unsigned long)context, dummy;
+ acpi_handle tmp;
+
+ status = acpi_get_handle(handle, "_OSC", &tmp);
+ if (ACPI_FAILURE(status))
+ return AE_OK;
+
+ 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");
+ goto out;
+ }
+
+ __acpi_query_osc(flags, osc_data, &dummy);
+out:
+ mutex_unlock(&pci_acpi_lock);
+ return AE_OK;
+}
+
/**
* __pci_osc_support_set - register OS support to Firmware
* @flags: OS support bits
@@ -181,7 +192,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;
+ u32 ctrlset, control_set, result;
acpi_handle tmp;
struct acpi_osc_data *osc_data;
struct acpi_osc_args osc_args;
@@ -190,19 +201,28 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
if (ACPI_FAILURE(status))
return status;
+ 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");
- return AE_ERROR;
+ status = AE_ERROR;
+ goto out;
}
ctrlset = (flags & OSC_CONTROL_MASKS);
- if (!ctrlset)
- return AE_TYPE;
+ if (!ctrlset) {
+ status = AE_TYPE;
+ goto out;
+ }
- if (osc_data->is_queried &&
- ((osc_data->query_result & ctrlset) != ctrlset))
- return AE_SUPPORT;
+ status = __acpi_query_osc(osc_data->support_set, osc_data, &result);
+ if (ACPI_FAILURE(status))
+ goto out;
+
+ if ((result & ctrlset) != ctrlset) {
+ status = AE_SUPPORT;
+ goto out;
+ }
control_set = osc_data->control_set | ctrlset;
osc_args.capbuf[OSC_QUERY_TYPE] = 0;
@@ -211,7 +231,8 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
status = acpi_run_osc(handle, &osc_args);
if (ACPI_SUCCESS(status))
osc_data->control_set = control_set;
-
+out:
+ mutex_unlock(&pci_acpi_lock);
return status;
}
EXPORT_SYMBOL(pci_osc_control_set);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index a13f5348611..b4cdd690ae7 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -43,18 +43,32 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
{
struct pci_dynid *dynid;
struct pci_driver *pdrv = to_pci_driver(driver);
+ const struct pci_device_id *ids = pdrv->id_table;
__u32 vendor, device, subvendor=PCI_ANY_ID,
subdevice=PCI_ANY_ID, class=0, class_mask=0;
unsigned long driver_data=0;
int fields=0;
- int retval = 0;
+ int retval;
- fields = sscanf(buf, "%x %x %x %x %x %x %lux",
+ fields = sscanf(buf, "%x %x %x %x %x %x %lx",
&vendor, &device, &subvendor, &subdevice,
&class, &class_mask, &driver_data);
if (fields < 2)
return -EINVAL;
+ /* 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;
+ }
+ ids++;
+ }
+ if (retval) /* No match */
+ return retval;
+
dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
if (!dynid)
return -ENOMEM;
@@ -65,8 +79,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
dynid->id.subdevice = subdevice;
dynid->id.class = class;
dynid->id.class_mask = class_mask;
- dynid->id.driver_data = pdrv->dynids.use_driver_data ?
- driver_data : 0UL;
+ dynid->id.driver_data = driver_data;
spin_lock(&pdrv->dynids.lock);
list_add_tail(&dynid->node, &pdrv->dynids.list);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 77baff022f7..110022d7868 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -423,7 +423,7 @@ pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr,
* Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific
* callback routine (pci_legacy_read).
*/
-ssize_t
+static ssize_t
pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
@@ -448,7 +448,7 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
* Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific
* callback routine (pci_legacy_write).
*/
-ssize_t
+static ssize_t
pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
@@ -468,11 +468,11 @@ pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
* @attr: struct bin_attribute for this file
* @vma: struct vm_area_struct passed to mmap
*
- * Uses an arch specific callback, pci_mmap_legacy_page_range, to mmap
+ * Uses an arch specific callback, pci_mmap_legacy_mem_page_range, to mmap
* legacy memory space (first meg of bus space) into application virtual
* memory space.
*/
-int
+static int
pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
struct vm_area_struct *vma)
{
@@ -480,7 +480,90 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
struct device,
kobj));
- return pci_mmap_legacy_page_range(bus, vma);
+ return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem);
+}
+
+/**
+ * pci_mmap_legacy_io - map legacy PCI IO into user memory space
+ * @kobj: kobject corresponding to device to be mapped
+ * @attr: struct bin_attribute for this file
+ * @vma: struct vm_area_struct passed to mmap
+ *
+ * Uses an arch specific callback, pci_mmap_legacy_io_page_range, to mmap
+ * legacy IO space (first meg of bus space) into application virtual
+ * memory space. Returns -ENOSYS if the operation isn't supported
+ */
+static int
+pci_mmap_legacy_io(struct kobject *kobj, struct bin_attribute *attr,
+ struct vm_area_struct *vma)
+{
+ struct pci_bus *bus = to_pci_bus(container_of(kobj,
+ struct device,
+ kobj));
+
+ return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io);
+}
+
+/**
+ * pci_create_legacy_files - create legacy I/O port and memory files
+ * @b: bus to create files under
+ *
+ * Some platforms allow access to legacy I/O port and ISA memory space on
+ * a per-bus basis. This routine creates the files and ties them into
+ * their associated read, write and mmap files from pci-sysfs.c
+ *
+ * On error unwind, but don't propogate the error to the caller
+ * as it is ok to set up the PCI bus without these files.
+ */
+void pci_create_legacy_files(struct pci_bus *b)
+{
+ int error;
+
+ b->legacy_io = kzalloc(sizeof(struct bin_attribute) * 2,
+ GFP_ATOMIC);
+ if (!b->legacy_io)
+ goto kzalloc_err;
+
+ b->legacy_io->attr.name = "legacy_io";
+ b->legacy_io->size = 0xffff;
+ b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
+ b->legacy_io->read = pci_read_legacy_io;
+ b->legacy_io->write = pci_write_legacy_io;
+ b->legacy_io->mmap = pci_mmap_legacy_io;
+ error = device_create_bin_file(&b->dev, b->legacy_io);
+ if (error)
+ goto legacy_io_err;
+
+ /* Allocated above after the legacy_io struct */
+ b->legacy_mem = b->legacy_io + 1;
+ b->legacy_mem->attr.name = "legacy_mem";
+ b->legacy_mem->size = 1024*1024;
+ b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
+ b->legacy_mem->mmap = pci_mmap_legacy_mem;
+ error = device_create_bin_file(&b->dev, b->legacy_mem);
+ if (error)
+ goto legacy_mem_err;
+
+ return;
+
+legacy_mem_err:
+ device_remove_bin_file(&b->dev, b->legacy_io);
+legacy_io_err:
+ kfree(b->legacy_io);
+ b->legacy_io = NULL;
+kzalloc_err:
+ printk(KERN_WARNING "pci: warning: could not create legacy I/O port "
+ "and ISA memory resources to sysfs\n");
+ return;
+}
+
+void pci_remove_legacy_files(struct pci_bus *b)
+{
+ if (b->legacy_io) {
+ device_remove_bin_file(&b->dev, b->legacy_io);
+ device_remove_bin_file(&b->dev, b->legacy_mem);
+ kfree(b->legacy_io); /* both are allocated here */
+ }
}
#endif /* HAVE_PCI_LEGACY */
@@ -715,7 +798,7 @@ static struct bin_attribute pci_config_attr = {
.name = "config",
.mode = S_IRUGO | S_IWUSR,
},
- .size = 256,
+ .size = PCI_CFG_SPACE_SIZE,
.read = pci_read_config,
.write = pci_write_config,
};
@@ -725,7 +808,7 @@ static struct bin_attribute pcie_config_attr = {
.name = "config",
.mode = S_IRUGO | S_IWUSR,
},
- .size = 4096,
+ .size = PCI_CFG_SPACE_EXP_SIZE,
.read = pci_read_config,
.write = pci_write_config,
};
@@ -735,86 +818,103 @@ int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
return 0;
}
+static int pci_create_capabilities_sysfs(struct pci_dev *dev)
+{
+ int retval;
+ struct bin_attribute *attr;
+
+ /* If the device has VPD, try to expose it in sysfs. */
+ if (dev->vpd) {
+ attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
+ if (!attr)
+ return -ENOMEM;
+
+ 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;
+ retval = sysfs_create_bin_file(&dev->dev.kobj, attr);
+ if (retval) {
+ kfree(dev->vpd->attr);
+ return retval;
+ }
+ dev->vpd->attr = attr;
+ }
+
+ /* Active State Power Management */
+ pcie_aspm_create_sysfs_dev_files(dev);
+
+ return 0;
+}
+
int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
{
- struct bin_attribute *attr = NULL;
int retval;
+ int rom_size = 0;
+ struct bin_attribute *attr;
if (!sysfs_initialized)
return -EACCES;
- if (pdev->cfg_size < 4096)
+ if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
else
retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
if (retval)
goto err;
- /* If the device has VPD, try to expose it in sysfs. */
- if (pdev->vpd) {
- attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
- if (attr) {
- pdev->vpd->attr = attr;
- attr->size = pdev->vpd->len;
- attr->attr.name = "vpd";
- attr->attr.mode = S_IRUSR | S_IWUSR;
- attr->read = pci_read_vpd;
- attr->write = pci_write_vpd;
- retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
- if (retval)
- goto err_vpd;
- } else {
- retval = -ENOMEM;
- goto err_config_file;
- }
- }
-
retval = pci_create_resource_files(pdev);
if (retval)
- goto err_vpd_file;
+ goto err_config_file;
+
+ if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
+ rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+ else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
+ rom_size = 0x20000;
/* If the device has a ROM, try to expose it in sysfs. */
- if (pci_resource_len(pdev, PCI_ROM_RESOURCE) ||
- (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) {
+ if (rom_size) {
attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
- if (attr) {
- pdev->rom_attr = attr;
- attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
- attr->attr.name = "rom";
- attr->attr.mode = S_IRUSR;
- attr->read = pci_read_rom;
- attr->write = pci_write_rom;
- retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
- if (retval)
- goto err_rom;
- } else {
+ if (!attr) {
retval = -ENOMEM;
goto err_resource_files;
}
+ attr->size = rom_size;
+ attr->attr.name = "rom";
+ attr->attr.mode = S_IRUSR;
+ attr->read = pci_read_rom;
+ attr->write = pci_write_rom;
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
+ if (retval) {
+ kfree(attr);
+ goto err_resource_files;
+ }
+ pdev->rom_attr = attr;
}
+
/* add platform-specific attributes */
- if (pcibios_add_platform_entries(pdev))
+ retval = pcibios_add_platform_entries(pdev);
+ if (retval)
goto err_rom_file;
- pcie_aspm_create_sysfs_dev_files(pdev);
+ /* add sysfs entries for various capabilities */
+ retval = pci_create_capabilities_sysfs(pdev);
+ if (retval)
+ goto err_rom_file;
return 0;
err_rom_file:
- if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
+ if (rom_size) {
sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
-err_rom:
- kfree(pdev->rom_attr);
+ kfree(pdev->rom_attr);
+ pdev->rom_attr = NULL;
+ }
err_resource_files:
pci_remove_resource_files(pdev);
-err_vpd_file:
- if (pdev->vpd) {
- sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr);
-err_vpd:
- kfree(pdev->vpd->attr);
- }
err_config_file:
- if (pdev->cfg_size < 4096)
+ if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
else
sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
@@ -822,6 +922,16 @@ err:
return retval;
}
+static void pci_remove_capabilities_sysfs(struct pci_dev *dev)
+{
+ if (dev->vpd && dev->vpd->attr) {
+ sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr);
+ kfree(dev->vpd->attr);
+ }
+
+ pcie_aspm_remove_sysfs_dev_files(dev);
+}
+
/**
* pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
* @pdev: device whose entries we should free
@@ -830,27 +940,28 @@ err:
*/
void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
{
+ int rom_size = 0;
+
if (!sysfs_initialized)
return;
- pcie_aspm_remove_sysfs_dev_files(pdev);
+ pci_remove_capabilities_sysfs(pdev);
- if (pdev->vpd) {
- sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr);
- kfree(pdev->vpd->attr);
- }
- if (pdev->cfg_size < 4096)
+ if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
else
sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
pci_remove_resource_files(pdev);
- if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
- if (pdev->rom_attr) {
- sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
- kfree(pdev->rom_attr);
- }
+ if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
+ rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+ else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
+ rom_size = 0x20000;
+
+ if (rom_size && pdev->rom_attr) {
+ sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
+ kfree(pdev->rom_attr);
}
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index c9884bba22d..533aeb5fcbe 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -18,6 +18,7 @@
#include <linux/log2.h>
#include <linux/pci-aspm.h>
#include <linux/pm_wakeup.h>
+#include <linux/interrupt.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
@@ -213,10 +214,13 @@ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
int pci_find_ext_capability(struct pci_dev *dev, int cap)
{
u32 header;
- int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
- int pos = 0x100;
+ int ttl;
+ int pos = PCI_CFG_SPACE_SIZE;
- if (dev->cfg_size <= 256)
+ /* minimum 8 bytes per capability */
+ ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+
+ if (dev->cfg_size <= PCI_CFG_SPACE_SIZE)
return 0;
if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
@@ -234,7 +238,7 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap)
return pos;
pos = PCI_EXT_CAP_NEXT(header);
- if (pos < 0x100)
+ if (pos < PCI_CFG_SPACE_SIZE)
break;
if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
@@ -1127,6 +1131,27 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
}
/**
+ * pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold
+ * @dev: PCI device to prepare
+ * @enable: True to enable wake-up event generation; false to disable
+ *
+ * Many drivers want the device to wake up the system from D3_hot or D3_cold
+ * and this function allows them to set that up cleanly - pci_enable_wake()
+ * should not be called twice in a row to enable wake-up due to PCI PM vs ACPI
+ * ordering constraints.
+ *
+ * This function only returns error code if the device is not capable of
+ * generating PME# from both D3_hot and D3_cold, and the platform is unable to
+ * enable wake-up power for it.
+ */
+int pci_wake_from_d3(struct pci_dev *dev, bool enable)
+{
+ return pci_pme_capable(dev, PCI_D3cold) ?
+ pci_enable_wake(dev, PCI_D3cold, enable) :
+ pci_enable_wake(dev, PCI_D3hot, enable);
+}
+
+/**
* pci_target_state - find an appropriate low power state for a given PCI dev
* @dev: PCI device
*
@@ -1242,25 +1267,25 @@ void pci_pm_init(struct pci_dev *dev)
dev->d1_support = false;
dev->d2_support = false;
if (!pci_no_d1d2(dev)) {
- if (pmc & PCI_PM_CAP_D1) {
- dev_printk(KERN_DEBUG, &dev->dev, "supports D1\n");
+ if (pmc & PCI_PM_CAP_D1)
dev->d1_support = true;
- }
- if (pmc & PCI_PM_CAP_D2) {
- dev_printk(KERN_DEBUG, &dev->dev, "supports D2\n");
+ if (pmc & PCI_PM_CAP_D2)
dev->d2_support = true;
- }
+
+ if (dev->d1_support || dev->d2_support)
+ dev_printk(KERN_DEBUG, &dev->dev, "supports%s%s\n",
+ dev->d1_support ? " D1" : "",
+ dev->d2_support ? " D2" : "");
}
pmc &= PCI_PM_CAP_PME_MASK;
if (pmc) {
- dev_printk(KERN_INFO, &dev->dev,
- "PME# supported from%s%s%s%s%s\n",
- (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
- (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
- (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
- (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "",
- (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
+ dev_info(&dev->dev, "PME# supported from%s%s%s%s%s\n",
+ (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
+ (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
+ (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
+ (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "",
+ (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT;
/*
* Make device's PM flags reflect the wake-up capability, but
@@ -1275,6 +1300,38 @@ void pci_pm_init(struct pci_dev *dev)
}
}
+/**
+ * pci_enable_ari - enable ARI forwarding if hardware support it
+ * @dev: the PCI device
+ */
+void pci_enable_ari(struct pci_dev *dev)
+{
+ int pos;
+ u32 cap;
+ u16 ctrl;
+
+ if (!dev->is_pcie)
+ return;
+
+ if (dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
+ dev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
+ return;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return;
+
+ pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP2, &cap);
+ if (!(cap & PCI_EXP_DEVCAP2_ARI))
+ return;
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
+ ctrl |= PCI_EXP_DEVCTL2_ARI;
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+
+ dev->ari_enabled = 1;
+}
+
int
pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
{
@@ -1358,11 +1415,10 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
return 0;
err_out:
- dev_warn(&pdev->dev, "BAR %d: can't reserve %s region [%#llx-%#llx]\n",
+ dev_warn(&pdev->dev, "BAR %d: can't reserve %s region %pR\n",
bar,
pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
- (unsigned long long)pci_resource_start(pdev, bar),
- (unsigned long long)pci_resource_end(pdev, bar));
+ &pdev->resource[bar]);
return -EBUSY;
}
@@ -1691,6 +1747,103 @@ 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)
+{
+ u16 status;
+ u32 cap;
+ int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+
+ if (!exppos)
+ return -ENOTTY;
+ pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap);
+ if (!(cap & PCI_EXP_DEVCAP_FLR))
+ return -ENOTTY;
+
+ pci_block_user_cfg_access(dev);
+
+ /* Wait for Transaction Pending bit clean */
+ msleep(100);
+ pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
+ if (status & PCI_EXP_DEVSTA_TRPND) {
+ dev_info(&dev->dev, "Busy after 100ms while trying to reset; "
+ "sleeping for 1 second\n");
+ ssleep(1);
+ pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status);
+ if (status & PCI_EXP_DEVSTA_TRPND)
+ dev_info(&dev->dev, "Still busy after 1s; "
+ "proceeding with reset anyway\n");
+ }
+
+ pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_BCR_FLR);
+ mdelay(100);
+
+ pci_unblock_user_cfg_access(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pci_execute_reset_function);
+
+/**
+ * pci_reset_function() - quiesce and 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.
+ *
+ * This function does not just reset the PCI portion of a device, but
+ * clears all the state associated with the device. This function differs
+ * from pci_execute_reset_function in that it saves and restores device state
+ * over the reset.
+ *
+ * Returns 0 if the device function was successfully reset or -ENOTTY if the
+ * device doesn't support resetting a single function.
+ */
+int pci_reset_function(struct pci_dev *dev)
+{
+ u32 cap;
+ int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ int r;
+
+ if (!exppos)
+ return -ENOTTY;
+ pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap);
+ if (!(cap & PCI_EXP_DEVCAP_FLR))
+ return -ENOTTY;
+
+ if (!dev->msi_enabled && !dev->msix_enabled)
+ disable_irq(dev->irq);
+ pci_save_state(dev);
+
+ pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
+
+ r = pci_execute_reset_function(dev);
+
+ pci_restore_state(dev);
+ if (!dev->msi_enabled && !dev->msix_enabled)
+ enable_irq(dev->irq);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(pci_reset_function);
+
+/**
* pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
* @dev: PCI device to query
*
@@ -1878,6 +2031,9 @@ static int __devinit pci_init(void)
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_fixup_device(pci_fixup_final, dev);
}
+
+ msi_init();
+
return 0;
}
@@ -1943,6 +2099,7 @@ EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_pme_capable);
EXPORT_SYMBOL(pci_pme_active);
EXPORT_SYMBOL(pci_enable_wake);
+EXPORT_SYMBOL(pci_wake_from_d3);
EXPORT_SYMBOL(pci_target_state);
EXPORT_SYMBOL(pci_prepare_to_sleep);
EXPORT_SYMBOL(pci_back_from_sleep);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index d807cd786f2..9de87e9f98f 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,3 +1,9 @@
+#ifndef DRIVERS_PCI_H
+#define DRIVERS_PCI_H
+
+#define PCI_CFG_SPACE_SIZE 256
+#define PCI_CFG_SPACE_EXP_SIZE 4096
+
/* Functions internal to the PCI core code */
extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
@@ -76,7 +82,13 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
/* Functions for PCI Hotplug drivers to use */
extern unsigned int pci_do_scan_bus(struct pci_bus *bus);
+#ifdef HAVE_PCI_LEGACY
+extern void pci_create_legacy_files(struct pci_bus *bus);
extern void pci_remove_legacy_files(struct pci_bus *bus);
+#else
+static inline void pci_create_legacy_files(struct pci_bus *bus) { return; }
+static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; }
+#endif
/* Lock for read/write access to pci device and bus lists */
extern struct rw_semaphore pci_bus_sem;
@@ -86,9 +98,11 @@ 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
@@ -109,6 +123,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
extern int pcie_mch_quirk;
extern struct device_attribute pci_dev_attrs[];
extern struct device_attribute dev_attr_cpuaffinity;
+extern struct device_attribute dev_attr_cpulistaffinity;
/**
* pci_match_one_device - Tell if a PCI device structure has a matching
@@ -144,3 +159,16 @@ struct pci_slot_attribute {
};
#define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr)
+extern void pci_enable_ari(struct pci_dev *dev);
+/**
+ * pci_ari_enabled - query ARI forwarding status
+ * @dev: the PCI device
+ *
+ * Returns 1 if ARI forwarding is enabled, or 0 if not enabled;
+ */
+static inline int pci_ari_enabled(struct pci_dev *dev)
+{
+ return dev->ari_enabled;
+}
+
+#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 77036f46acf..e390707661d 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -105,7 +105,7 @@ static irqreturn_t aer_irq(int irq, void *context)
unsigned long flags;
int pos;
- pos = pci_find_aer_capability(pdev->port);
+ pos = pci_find_ext_capability(pdev->port, PCI_EXT_CAP_ID_ERR);
/*
* Must lock access to Root Error Status Reg, Root Error ID Reg,
* and Root error producer/consumer index
@@ -252,7 +252,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
u32 status;
int pos;
- pos = pci_find_aer_capability(dev);
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
/* Disable Root's interrupt in response to error messages */
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0);
@@ -316,7 +316,7 @@ static void aer_error_resume(struct pci_dev *dev)
pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
/* Clean AER Root Error Status */
- pos = pci_find_aer_capability(dev);
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
if (dev->error_state == pci_channel_io_normal)
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index ee5e7b5176d..dfc63d01f20 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -28,41 +28,15 @@
static int forceload;
module_param(forceload, bool, 0);
-#define PCI_CFG_SPACE_SIZE (0x100)
-int pci_find_aer_capability(struct pci_dev *dev)
-{
- int pos;
- u32 reg32 = 0;
-
- /* Check if it's a pci-express device */
- pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
- if (!pos)
- return 0;
-
- /* Check if it supports pci-express AER */
- pos = PCI_CFG_SPACE_SIZE;
- while (pos) {
- if (pci_read_config_dword(dev, pos, &reg32))
- return 0;
-
- /* some broken boards return ~0 */
- if (reg32 == 0xffffffff)
- return 0;
-
- if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
- break;
-
- pos = reg32 >> 20;
- }
-
- return pos;
-}
-
int pci_enable_pcie_error_reporting(struct pci_dev *dev)
{
u16 reg16 = 0;
int pos;
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ if (!pos)
+ return -EIO;
+
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (!pos)
return -EIO;
@@ -102,7 +76,7 @@ int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
int pos;
u32 status, mask;
- pos = pci_find_aer_capability(dev);
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return -EIO;
@@ -123,7 +97,7 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
int pos;
u32 status;
- pos = pci_find_aer_capability(dev);
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return -EIO;
@@ -502,7 +476,7 @@ static void handle_error_source(struct pcie_device * aerdev,
* Correctable error does not need software intevention.
* No need to go through error recovery process.
*/
- pos = pci_find_aer_capability(dev);
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (pos)
pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
info.status);
@@ -542,7 +516,7 @@ void aer_enable_rootport(struct aer_rpc *rpc)
reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
- aer_pos = pci_find_aer_capability(pdev);
+ aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
/* Clear error status */
pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
@@ -579,7 +553,7 @@ static void disable_root_aer(struct aer_rpc *rpc)
u32 reg32;
int pos;
- pos = pci_find_aer_capability(pdev);
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
/* Disable Root's interrupt in response to error messages */
pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);
@@ -618,7 +592,7 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
{
int pos;
- pos = pci_find_aer_capability(dev);
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
/* The device might not support AER */
if (!pos)
@@ -755,7 +729,6 @@ int aer_init(struct pcie_device *dev)
return AER_SUCCESS;
}
-EXPORT_SYMBOL_GPL(pci_find_aer_capability);
EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 851f5b83cdb..8f63f4c6b85 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -528,9 +528,9 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP,
&reg32);
if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) {
- printk("Pre-1.1 PCIe device detected, "
- "disable ASPM for %s. It can be enabled forcedly"
- " with 'pcie_aspm=force'\n", pci_name(pdev));
+ dev_printk(KERN_INFO, &child_dev->dev, "disabling ASPM"
+ " on pre-1.1 PCIe device. You can enable it"
+ " with 'pcie_aspm=force'\n");
return -EINVAL;
}
}
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 3656e0349dd..2529f3f2ea5 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -25,7 +25,6 @@
#define PCIE_CAPABILITIES_REG 0x2
#define PCIE_SLOT_CAPABILITIES_REG 0x14
#define PCIE_PORT_DEVICE_MAXSERVICES 4
-#define PCI_CFG_SPACE_SIZE 256
#define get_descriptor_id(type, service) (((type - 4) << 4) | service)
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 890f0d2b370..2e091e01482 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -195,24 +195,11 @@ static int get_port_device_capability(struct pci_dev *dev)
/* PME Capable - root port capability */
if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT)
services |= PCIE_PORT_SERVICE_PME;
-
- pos = PCI_CFG_SPACE_SIZE;
- while (pos) {
- pci_read_config_dword(dev, pos, &reg32);
- switch (reg32 & 0xffff) {
- case PCI_EXT_CAP_ID_ERR:
- services |= PCIE_PORT_SERVICE_AER;
- pos = reg32 >> 20;
- break;
- case PCI_EXT_CAP_ID_VC:
- services |= PCIE_PORT_SERVICE_VC;
- pos = reg32 >> 20;
- break;
- default:
- pos = 0;
- break;
- }
- }
+
+ if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
+ services |= PCIE_PORT_SERVICE_AER;
+ if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
+ services |= PCIE_PORT_SERVICE_VC;
return services;
}
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 367c9c20000..584422da8d8 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -91,7 +91,7 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
pci_set_master(dev);
if (!dev->irq && dev->pin) {
- dev_warn(&dev->dev, "device [%04x/%04x] has invalid IRQ; "
+ dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; "
"check vendor BIOS\n", dev->vendor, dev->device);
}
if (pcie_port_device_register(dev)) {
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index dd9161a054e..6f1e51d77bc 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -14,8 +14,6 @@
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR 3
-#define PCI_CFG_SPACE_SIZE 256
-#define PCI_CFG_SPACE_EXP_SIZE 4096
/* Ugh. Need to stop exporting this to modules. */
LIST_HEAD(pci_root_buses);
@@ -44,72 +42,6 @@ int no_pci_devices(void)
}
EXPORT_SYMBOL(no_pci_devices);
-#ifdef HAVE_PCI_LEGACY
-/**
- * pci_create_legacy_files - create legacy I/O port and memory files
- * @b: bus to create files under
- *
- * Some platforms allow access to legacy I/O port and ISA memory space on
- * a per-bus basis. This routine creates the files and ties them into
- * their associated read, write and mmap files from pci-sysfs.c
- *
- * On error unwind, but don't propogate the error to the caller
- * as it is ok to set up the PCI bus without these files.
- */
-static void pci_create_legacy_files(struct pci_bus *b)
-{
- int error;
-
- b->legacy_io = kzalloc(sizeof(struct bin_attribute) * 2,
- GFP_ATOMIC);
- if (!b->legacy_io)
- goto kzalloc_err;
-
- b->legacy_io->attr.name = "legacy_io";
- b->legacy_io->size = 0xffff;
- b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
- b->legacy_io->read = pci_read_legacy_io;
- b->legacy_io->write = pci_write_legacy_io;
- error = device_create_bin_file(&b->dev, b->legacy_io);
- if (error)
- goto legacy_io_err;
-
- /* Allocated above after the legacy_io struct */
- b->legacy_mem = b->legacy_io + 1;
- b->legacy_mem->attr.name = "legacy_mem";
- b->legacy_mem->size = 1024*1024;
- b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
- b->legacy_mem->mmap = pci_mmap_legacy_mem;
- error = device_create_bin_file(&b->dev, b->legacy_mem);
- if (error)
- goto legacy_mem_err;
-
- return;
-
-legacy_mem_err:
- device_remove_bin_file(&b->dev, b->legacy_io);
-legacy_io_err:
- kfree(b->legacy_io);
- b->legacy_io = NULL;
-kzalloc_err:
- printk(KERN_WARNING "pci: warning: could not create legacy I/O port "
- "and ISA memory resources to sysfs\n");
- return;
-}
-
-void pci_remove_legacy_files(struct pci_bus *b)
-{
- if (b->legacy_io) {
- device_remove_bin_file(&b->dev, b->legacy_io);
- device_remove_bin_file(&b->dev, b->legacy_mem);
- kfree(b->legacy_io); /* both are allocated here */
- }
-}
-#else /* !HAVE_PCI_LEGACY */
-static inline void pci_create_legacy_files(struct pci_bus *bus) { return; }
-void pci_remove_legacy_files(struct pci_bus *bus) { return; }
-#endif /* HAVE_PCI_LEGACY */
-
/*
* PCI Bus Class Devices
*/
@@ -219,7 +151,7 @@ static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar)
res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK;
- if (res->flags == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ if (res->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
return pci_bar_mem64;
return pci_bar_mem32;
}
@@ -304,9 +236,8 @@ static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
} else {
res->start = l64;
res->end = l64 + sz64;
- printk(KERN_DEBUG "PCI: %s reg %x 64bit mmio: [%llx, %llx]\n",
- pci_name(dev), pos, (unsigned long long)res->start,
- (unsigned long long)res->end);
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "reg %x 64bit mmio: %pR\n", pos, res);
}
} else {
sz = pci_size(l, sz, mask);
@@ -316,9 +247,10 @@ static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->start = l;
res->end = l + sz;
- printk(KERN_DEBUG "PCI: %s reg %x %s: [%llx, %llx]\n", pci_name(dev),
- pos, (res->flags & IORESOURCE_IO) ? "io port":"32bit mmio",
- (unsigned long long)res->start, (unsigned long long)res->end);
+
+ dev_printk(KERN_DEBUG, &dev->dev, "reg %x %s: %pR\n", pos,
+ (res->flags & IORESOURCE_IO) ? "io port" : "32bit mmio",
+ res);
}
out:
@@ -389,9 +321,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->start = base;
if (!res->end)
res->end = limit + 0xfff;
- printk(KERN_DEBUG "PCI: bridge %s io port: [%llx, %llx]\n",
- pci_name(dev), (unsigned long long) res->start,
- (unsigned long long) res->end);
+ dev_printk(KERN_DEBUG, &dev->dev, "bridge io port: %pR\n", res);
}
res = child->resource[1];
@@ -403,9 +333,8 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
res->start = base;
res->end = limit + 0xfffff;
- printk(KERN_DEBUG "PCI: bridge %s 32bit mmio: [%llx, %llx]\n",
- pci_name(dev), (unsigned long long) res->start,
- (unsigned long long) res->end);
+ dev_printk(KERN_DEBUG, &dev->dev, "bridge 32bit mmio: %pR\n",
+ res);
}
res = child->resource[2];
@@ -441,9 +370,9 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
res->start = base;
res->end = limit + 0xfffff;
- printk(KERN_DEBUG "PCI: bridge %s %sbit mmio pref: [%llx, %llx]\n",
- pci_name(dev), (res->flags & PCI_PREF_RANGE_TYPE_64) ? "64" : "32",
- (unsigned long long) res->start, (unsigned long long) res->end);
+ dev_printk(KERN_DEBUG, &dev->dev, "bridge %sbit mmio pref: %pR\n",
+ (res->flags & PCI_PREF_RANGE_TYPE_64) ? "64" : "32",
+ res);
}
}
@@ -551,19 +480,27 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
u32 buses, i, j = 0;
u16 bctl;
+ int broken = 0;
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
dev_dbg(&dev->dev, "scanning behind bridge, config %06x, pass %d\n",
buses & 0xffffff, pass);
+ /* Check if setup is sensible at all */
+ if (!pass &&
+ ((buses & 0xff) != bus->number || ((buses >> 8) & 0xff) <= bus->number)) {
+ dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n");
+ broken = 1;
+ }
+
/* Disable MasterAbortMode during probing to avoid reporting
of bus errors (in some architectures) */
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl);
pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
- if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) {
+ if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus && !broken) {
unsigned int cmax, busnr;
/*
* Bus already configured by firmware, process it in the first
@@ -601,7 +538,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
* do in the second pass.
*/
if (!pass) {
- if (pcibios_assign_all_busses())
+ if (pcibios_assign_all_busses() || broken)
/* Temporarily disable forwarding of the
configuration cycles on all bridges in
this bus segment to avoid possible
@@ -764,7 +701,7 @@ static int pci_setup_device(struct pci_dev * dev)
dev->class = class;
class >>= 8;
- dev_dbg(&dev->dev, "found [%04x/%04x] class %06x header type %02x\n",
+ dev_dbg(&dev->dev, "found [%04x:%04x] class %06x header type %02x\n",
dev->vendor, dev->device, class, dev->hdr_type);
/* "Unknown power state" */
@@ -846,6 +783,11 @@ static int pci_setup_device(struct pci_dev * dev)
return 0;
}
+static void pci_release_capabilities(struct pci_dev *dev)
+{
+ pci_vpd_release(dev);
+}
+
/**
* pci_release_dev - free a pci device structure when all users of it are finished.
* @dev: device that's been disconnected
@@ -858,7 +800,7 @@ static void pci_release_dev(struct device *dev)
struct pci_dev *pci_dev;
pci_dev = to_pci_dev(dev);
- pci_vpd_release(pci_dev);
+ pci_release_capabilities(pci_dev);
kfree(pci_dev);
}
@@ -889,8 +831,9 @@ static void set_pcie_port_type(struct pci_dev *pdev)
int pci_cfg_space_size_ext(struct pci_dev *dev)
{
u32 status;
+ int pos = PCI_CFG_SPACE_SIZE;
- if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL)
+ if (pci_read_config_dword(dev, pos, &status) != PCIBIOS_SUCCESSFUL)
goto fail;
if (status == 0xffffffff)
goto fail;
@@ -938,8 +881,6 @@ struct pci_dev *alloc_pci_dev(void)
INIT_LIST_HEAD(&dev->bus_list);
- pci_msi_init_pci_dev(dev);
-
return dev;
}
EXPORT_SYMBOL(alloc_pci_dev);
@@ -951,6 +892,7 @@ EXPORT_SYMBOL(alloc_pci_dev);
static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
+ struct pci_slot *slot;
u32 l;
u8 hdr_type;
int delay = 1;
@@ -999,6 +941,10 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
dev->error_state = pci_channel_io_normal;
set_pcie_port_type(dev);
+ list_for_each_entry(slot, &bus->slots, list)
+ if (PCI_SLOT(devfn) == slot->number)
+ dev->slot = slot;
+
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
set this higher, assuming the system even supports it. */
dev->dma_mask = 0xffffffff;
@@ -1007,9 +953,22 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
return NULL;
}
+ return dev;
+}
+
+static void pci_init_capabilities(struct pci_dev *dev)
+{
+ /* MSI/MSI-X list */
+ pci_msi_init_pci_dev(dev);
+
+ /* Power Management */
+ pci_pm_init(dev);
+
+ /* Vital Product Data */
pci_vpd_pci22_init(dev);
- return dev;
+ /* Alternative Routing-ID Forwarding */
+ pci_enable_ari(dev);
}
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
@@ -1028,8 +987,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
/* Fix up broken headers */
pci_fixup_device(pci_fixup_header, dev);
- /* Initialize power management of the device */
- pci_pm_init(dev);
+ /* Initialize various capabilities */
+ pci_init_capabilities(dev);
/*
* Add the device to our list of discovered devices
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index e872ac925b4..96cf8ecd04c 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -24,6 +24,14 @@
#include <linux/kallsyms.h>
#include "pci.h"
+int isa_dma_bridge_buggy;
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
+int pci_pci_problems;
+EXPORT_SYMBOL(pci_pci_problems);
+int pcie_mch_quirk;
+EXPORT_SYMBOL(pcie_mch_quirk);
+
+#ifdef CONFIG_PCI_QUIRKS
/* The Mellanox Tavor device gives false positive parity errors
* Mark this device with a broken_parity_status, to allow
* PCI scanning code to "skip" this now blacklisted device.
@@ -35,6 +43,20 @@ static void __devinit quirk_mellanox_tavor(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR,quirk_mellanox_tavor);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE,quirk_mellanox_tavor);
+/* Many VIA bridges seem to corrupt data for DAC. Disable it here */
+int forbid_dac __read_mostly;
+EXPORT_SYMBOL(forbid_dac);
+
+static __devinit void via_no_dac(struct pci_dev *dev)
+{
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
+ dev_info(&dev->dev,
+ "VIA PCI bridge detected. Disabling DAC.\n");
+ forbid_dac = 1;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac);
+
/* Deal with broken BIOS'es that neglect to enable passive release,
which can cause problems in combination with the 82441FX/PPro MTRRs */
static void quirk_passive_release(struct pci_dev *dev)
@@ -62,8 +84,6 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_p
This appears to be BIOS not version dependent. So presumably there is a
chipset level fix */
-int isa_dma_bridge_buggy;
-EXPORT_SYMBOL(isa_dma_bridge_buggy);
static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
{
@@ -84,9 +104,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_d
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs);
-int pci_pci_problems;
-EXPORT_SYMBOL(pci_pci_problems);
-
/*
* Chipsets where PCI->PCI transfers vanish or hang
*/
@@ -1362,9 +1379,6 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic);
#endif
-int pcie_mch_quirk;
-EXPORT_SYMBOL(pcie_mch_quirk);
-
static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
{
pcie_mch_quirk = 1;
@@ -1555,84 +1569,6 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810);
-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)) {
-#ifdef DEBUG
- dev_dbg(&dev->dev, "calling %pF\n", f->hook);
-#endif
- f->hook(dev);
- }
- f++;
- }
-}
-
-extern struct pci_fixup __start_pci_fixups_early[];
-extern struct pci_fixup __end_pci_fixups_early[];
-extern struct pci_fixup __start_pci_fixups_header[];
-extern struct pci_fixup __end_pci_fixups_header[];
-extern struct pci_fixup __start_pci_fixups_final[];
-extern struct pci_fixup __end_pci_fixups_final[];
-extern struct pci_fixup __start_pci_fixups_enable[];
-extern struct pci_fixup __end_pci_fixups_enable[];
-extern struct pci_fixup __start_pci_fixups_resume[];
-extern struct pci_fixup __end_pci_fixups_resume[];
-extern struct pci_fixup __start_pci_fixups_resume_early[];
-extern struct pci_fixup __end_pci_fixups_resume_early[];
-extern struct pci_fixup __start_pci_fixups_suspend[];
-extern struct pci_fixup __end_pci_fixups_suspend[];
-
-
-void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
-{
- struct pci_fixup *start, *end;
-
- switch(pass) {
- case pci_fixup_early:
- start = __start_pci_fixups_early;
- end = __end_pci_fixups_early;
- break;
-
- case pci_fixup_header:
- start = __start_pci_fixups_header;
- end = __end_pci_fixups_header;
- break;
-
- case pci_fixup_final:
- start = __start_pci_fixups_final;
- end = __end_pci_fixups_final;
- break;
-
- case pci_fixup_enable:
- start = __start_pci_fixups_enable;
- end = __end_pci_fixups_enable;
- break;
-
- case pci_fixup_resume:
- start = __start_pci_fixups_resume;
- end = __end_pci_fixups_resume;
- break;
-
- case pci_fixup_resume_early:
- start = __start_pci_fixups_resume_early;
- end = __end_pci_fixups_resume_early;
- break;
-
- case pci_fixup_suspend:
- start = __start_pci_fixups_suspend;
- end = __end_pci_fixups_suspend;
- break;
-
- default:
- /* stupid compiler warning, you would think with an enum... */
- return;
- }
- pci_do_fixups(dev, start, end);
-}
-EXPORT_SYMBOL(pci_fixup_device);
-
/* Enable 1k I/O space granularity on the Intel P64H2 */
static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
{
@@ -2006,3 +1942,82 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375,
quirk_msi_intx_disable_bug);
#endif /* CONFIG_PCI_MSI */
+
+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)) {
+ dev_dbg(&dev->dev, "calling %pF\n", f->hook);
+ f->hook(dev);
+ }
+ f++;
+ }
+}
+
+extern struct pci_fixup __start_pci_fixups_early[];
+extern struct pci_fixup __end_pci_fixups_early[];
+extern struct pci_fixup __start_pci_fixups_header[];
+extern struct pci_fixup __end_pci_fixups_header[];
+extern struct pci_fixup __start_pci_fixups_final[];
+extern struct pci_fixup __end_pci_fixups_final[];
+extern struct pci_fixup __start_pci_fixups_enable[];
+extern struct pci_fixup __end_pci_fixups_enable[];
+extern struct pci_fixup __start_pci_fixups_resume[];
+extern struct pci_fixup __end_pci_fixups_resume[];
+extern struct pci_fixup __start_pci_fixups_resume_early[];
+extern struct pci_fixup __end_pci_fixups_resume_early[];
+extern struct pci_fixup __start_pci_fixups_suspend[];
+extern struct pci_fixup __end_pci_fixups_suspend[];
+
+
+void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
+{
+ struct pci_fixup *start, *end;
+
+ switch(pass) {
+ case pci_fixup_early:
+ start = __start_pci_fixups_early;
+ end = __end_pci_fixups_early;
+ break;
+
+ case pci_fixup_header:
+ start = __start_pci_fixups_header;
+ end = __end_pci_fixups_header;
+ break;
+
+ case pci_fixup_final:
+ start = __start_pci_fixups_final;
+ end = __end_pci_fixups_final;
+ break;
+
+ case pci_fixup_enable:
+ start = __start_pci_fixups_enable;
+ end = __end_pci_fixups_enable;
+ break;
+
+ case pci_fixup_resume:
+ start = __start_pci_fixups_resume;
+ end = __end_pci_fixups_resume;
+ break;
+
+ case pci_fixup_resume_early:
+ start = __start_pci_fixups_resume_early;
+ end = __end_pci_fixups_resume_early;
+ break;
+
+ case pci_fixup_suspend:
+ start = __start_pci_fixups_suspend;
+ end = __end_pci_fixups_suspend;
+ break;
+
+ default:
+ /* stupid compiler warning, you would think with an enum... */
+ return;
+ }
+ pci_do_fixups(dev, start, end);
+}
+#else
+void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {}
+#endif
+EXPORT_SYMBOL(pci_fixup_device);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index bdc2a44d68e..042e0892442 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -73,6 +73,7 @@ void pci_remove_bus(struct pci_bus *pci_bus)
up_write(&pci_bus_sem);
pci_remove_legacy_files(pci_bus);
device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity);
+ device_remove_file(&pci_bus->dev, &dev_attr_cpulistaffinity);
device_unregister(&pci_bus->dev);
}
EXPORT_SYMBOL(pci_remove_bus);
@@ -114,13 +115,9 @@ void pci_remove_behind_bridge(struct pci_dev *dev)
{
struct list_head *l, *n;
- if (dev->subordinate) {
- list_for_each_safe(l, n, &dev->subordinate->devices) {
- struct pci_dev *dev = pci_dev_b(l);
-
- pci_remove_bus_device(dev);
- }
- }
+ if (dev->subordinate)
+ list_for_each_safe(l, n, &dev->subordinate->devices)
+ pci_remove_bus_device(pci_dev_b(l));
}
static void pci_stop_bus_devices(struct pci_bus *bus)
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index bd5c0e03139..1f5f6143f35 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -21,7 +21,7 @@
* between the ROM and other resources, so enabling it may disable access
* to MMIO registers or other card memory.
*/
-static int pci_enable_rom(struct pci_dev *pdev)
+int pci_enable_rom(struct pci_dev *pdev)
{
struct resource *res = pdev->resource + PCI_ROM_RESOURCE;
struct pci_bus_region region;
@@ -45,7 +45,7 @@ static int pci_enable_rom(struct pci_dev *pdev)
* Disable ROM decoding on a PCI device by turning off the last bit in the
* ROM BAR.
*/
-static void pci_disable_rom(struct pci_dev *pdev)
+void pci_disable_rom(struct pci_dev *pdev)
{
u32 rom_addr;
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
@@ -260,3 +260,5 @@ void pci_cleanup_rom(struct pci_dev *pdev)
EXPORT_SYMBOL(pci_map_rom);
EXPORT_SYMBOL(pci_unmap_rom);
+EXPORT_SYMBOL_GPL(pci_enable_rom);
+EXPORT_SYMBOL_GPL(pci_disable_rom);
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 4edfc4731bd..5af8bd53814 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -166,6 +166,7 @@ struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device,
{
struct pci_dev *pdev;
+ pci_dev_get(from);
pdev = pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
pci_dev_put(pdev);
return pdev;
@@ -270,12 +271,8 @@ static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
struct pci_dev *pdev = NULL;
WARN_ON(in_interrupt());
- if (from) {
- /* FIXME
- * take the cast off, when bus_find_device is made const.
- */
- dev_start = (struct device *)&from->dev;
- }
+ if (from)
+ dev_start = &from->dev;
dev = bus_find_device(&pci_bus_type, dev_start, (void *)id,
match_pci_dev_by_id);
if (dev)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index d5e2106760f..ea979f2bc6d 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -299,7 +299,7 @@ static void pbus_size_io(struct pci_bus *bus)
if (r->parent || !(r->flags & IORESOURCE_IO))
continue;
- r_size = r->end - r->start + 1;
+ r_size = resource_size(r);
if (r_size < 0x400)
/* Might be re-aligned for ISA */
@@ -350,16 +350,13 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
if (r->parent || (r->flags & mask) != type)
continue;
- r_size = r->end - r->start + 1;
+ r_size = resource_size(r);
/* For bridges size != alignment */
align = resource_alignment(r);
order = __ffs(align) - 20;
if (order > 11) {
dev_warn(&dev->dev, "BAR %d bad alignment %llx: "
- "%#016llx-%#016llx\n", i,
- (unsigned long long)align,
- (unsigned long long)r->start,
- (unsigned long long)r->end);
+ "%pR\n", i, (unsigned long long)align, r);
r->flags = 0;
continue;
}
@@ -539,11 +536,9 @@ static void pci_bus_dump_res(struct pci_bus *bus)
if (!res)
continue;
- printk(KERN_INFO "bus: %02x index %x %s: [%llx, %llx]\n",
- bus->number, i,
- (res->flags & IORESOURCE_IO) ? "io port" : "mmio",
- (unsigned long long) res->start,
- (unsigned long long) res->end);
+ printk(KERN_INFO "bus: %02x index %x %s: %pR\n",
+ bus->number, i,
+ (res->flags & IORESOURCE_IO) ? "io port" : "mmio", res);
}
}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 1a5fc83c71b..2dbd96cce2d 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -49,10 +49,8 @@ void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
pcibios_resource_to_bus(dev, &region, res);
- dev_dbg(&dev->dev, "BAR %d: got res [%#llx-%#llx] bus [%#llx-%#llx] "
- "flags %#lx\n", resno,
- (unsigned long long)res->start,
- (unsigned long long)res->end,
+ dev_dbg(&dev->dev, "BAR %d: got res %pR bus [%#llx-%#llx] "
+ "flags %#lx\n", resno, res,
(unsigned long long)region.start,
(unsigned long long)region.end,
(unsigned long)res->flags);
@@ -114,13 +112,11 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
err = insert_resource(root, res);
if (err) {
- dev_err(&dev->dev, "BAR %d: %s of %s [%#llx-%#llx]\n",
+ dev_err(&dev->dev, "BAR %d: %s of %s %pR\n",
resource,
root ? "address space collision on" :
"no parent found for",
- dtype,
- (unsigned long long)res->start,
- (unsigned long long)res->end);
+ dtype, res);
}
return err;
@@ -133,15 +129,14 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
resource_size_t size, min, align;
int ret;
- size = res->end - res->start + 1;
+ size = resource_size(res);
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
align = resource_alignment(res);
if (!align) {
dev_err(&dev->dev, "BAR %d: can't allocate resource (bogus "
- "alignment) [%#llx-%#llx] flags %#lx\n",
- resno, (unsigned long long)res->start,
- (unsigned long long)res->end, res->flags);
+ "alignment) %pR flags %#lx\n",
+ resno, res, res->flags);
return -EINVAL;
}
@@ -162,11 +157,8 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
}
if (ret) {
- dev_err(&dev->dev, "BAR %d: can't allocate %s resource "
- "[%#llx-%#llx]\n", resno,
- res->flags & IORESOURCE_IO ? "I/O" : "mem",
- (unsigned long long)res->start,
- (unsigned long long)res->end);
+ dev_err(&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)
@@ -202,11 +194,8 @@ int pci_assign_resource_fixed(struct pci_dev *dev, int resno)
}
if (ret) {
- dev_err(&dev->dev, "BAR %d: can't allocate %s resource "
- "[%#llx-%#llx\n]", resno,
- res->flags & IORESOURCE_IO ? "I/O" : "mem",
- (unsigned long long)res->start,
- (unsigned long long)res->end);
+ 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);
}
@@ -237,9 +226,8 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
r_align = resource_alignment(r);
if (!r_align) {
dev_warn(&dev->dev, "BAR %d: bogus alignment "
- "[%#llx-%#llx] flags %#lx\n",
- i, (unsigned long long)r->start,
- (unsigned long long)r->end, r->flags);
+ "%pR flags %#lx\n",
+ i, r, r->flags);
continue;
}
for (list = head; ; list = list->next) {
@@ -287,9 +275,7 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
if (!r->parent) {
dev_err(&dev->dev, "device not available because of "
- "BAR %d [%#llx-%#llx] collisions\n", i,
- (unsigned long long) r->start,
- (unsigned long long) r->end);
+ "BAR %d %pR collisions\n", i, r);
return -EINVAL;
}
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index 7e5b85cbd94..4dd1c3e157a 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -49,11 +49,16 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf)
static void pci_slot_release(struct kobject *kobj)
{
+ struct pci_dev *dev;
struct pci_slot *slot = to_pci_slot(kobj);
pr_debug("%s: releasing pci_slot on %x:%d\n", __func__,
slot->bus->number, slot->number);
+ list_for_each_entry(dev, &slot->bus->devices, bus_list)
+ if (PCI_SLOT(dev->devfn) == slot->number)
+ dev->slot = NULL;
+
list_del(&slot->list);
kfree(slot);
@@ -73,18 +78,100 @@ static struct kobj_type pci_slot_ktype = {
.default_attrs = pci_slot_default_attrs,
};
+static char *make_slot_name(const char *name)
+{
+ char *new_name;
+ int len, max, dup;
+
+ new_name = kstrdup(name, GFP_KERNEL);
+ if (!new_name)
+ return NULL;
+
+ /*
+ * Make sure we hit the realloc case the first time through the
+ * loop. 'len' will be strlen(name) + 3 at that point which is
+ * enough space for "name-X" and the trailing NUL.
+ */
+ len = strlen(name) + 2;
+ max = 1;
+ dup = 1;
+
+ for (;;) {
+ struct kobject *dup_slot;
+ dup_slot = kset_find_obj(pci_slots_kset, new_name);
+ if (!dup_slot)
+ break;
+ kobject_put(dup_slot);
+ if (dup == max) {
+ len++;
+ max *= 10;
+ kfree(new_name);
+ new_name = kmalloc(len, GFP_KERNEL);
+ if (!new_name)
+ break;
+ }
+ sprintf(new_name, "%s-%d", name, dup++);
+ }
+
+ return new_name;
+}
+
+static int rename_slot(struct pci_slot *slot, const char *name)
+{
+ int result = 0;
+ char *slot_name;
+
+ if (strcmp(pci_slot_name(slot), name) == 0)
+ return result;
+
+ slot_name = make_slot_name(name);
+ if (!slot_name)
+ return -ENOMEM;
+
+ result = kobject_rename(&slot->kobj, slot_name);
+ kfree(slot_name);
+
+ return result;
+}
+
+static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
+{
+ struct pci_slot *slot;
+ /*
+ * We already hold pci_bus_sem so don't worry
+ */
+ list_for_each_entry(slot, &parent->slots, list)
+ if (slot->number == slot_nr) {
+ kobject_get(&slot->kobj);
+ return slot;
+ }
+
+ return NULL;
+}
+
/**
* pci_create_slot - create or increment refcount for physical PCI slot
* @parent: struct pci_bus of parent bridge
* @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder
* @name: user visible string presented in /sys/bus/pci/slots/<name>
+ * @hotplug: set if caller is hotplug driver, NULL otherwise
*
* PCI slots have first class attributes such as address, speed, width,
* and a &struct pci_slot is used to manage them. This interface will
* either return a new &struct pci_slot to the caller, or if the pci_slot
* already exists, its refcount will be incremented.
*
- * Slots are uniquely identified by a @pci_bus, @slot_nr, @name tuple.
+ * Slots are uniquely identified by a @pci_bus, @slot_nr tuple.
+ *
+ * There are known platforms with broken firmware that assign the same
+ * name to multiple slots. Workaround these broken platforms by renaming
+ * the slots on behalf of the caller. If firmware assigns name N to
+ * multiple slots:
+ *
+ * The first slot is assigned N
+ * The second slot is assigned N-1
+ * The third slot is assigned N-2
+ * etc.
*
* Placeholder slots:
* In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify
@@ -93,71 +180,82 @@ static struct kobj_type pci_slot_ktype = {
* the slot. In this scenario, the caller may pass -1 for @slot_nr.
*
* The following semantics are imposed when the caller passes @slot_nr ==
- * -1. First, the check for existing %struct pci_slot is skipped, as the
- * caller may know about several unpopulated slots on a given %struct
- * pci_bus, and each slot would have a @slot_nr of -1. Uniqueness for
- * these slots is then determined by the @name parameter. We expect
- * kobject_init_and_add() to warn us if the caller attempts to create
- * multiple slots with the same name. The other change in semantics is
+ * -1. First, we no longer check for an existing %struct pci_slot, as there
+ * may be many slots with @slot_nr of -1. The other change in semantics is
* user-visible, which is the 'address' parameter presented in sysfs will
* consist solely of a dddd:bb tuple, where dddd is the PCI domain of the
* %struct pci_bus and bb is the bus number. In other words, the devfn of
* the 'placeholder' slot will not be displayed.
*/
-
struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
- const char *name)
+ const char *name,
+ struct hotplug_slot *hotplug)
{
+ struct pci_dev *dev;
struct pci_slot *slot;
- int err;
+ int err = 0;
+ char *slot_name = NULL;
down_write(&pci_bus_sem);
if (slot_nr == -1)
goto placeholder;
- /* If we've already created this slot, bump refcount and return. */
- list_for_each_entry(slot, &parent->slots, list) {
- if (slot->number == slot_nr) {
- kobject_get(&slot->kobj);
- pr_debug("%s: inc refcount to %d on %04x:%02x:%02x\n",
- __func__,
- atomic_read(&slot->kobj.kref.refcount),
- pci_domain_nr(parent), parent->number,
- slot_nr);
- goto out;
+ /*
+ * Hotplug drivers are allowed to rename an existing slot,
+ * but only if not already claimed.
+ */
+ slot = get_slot(parent, slot_nr);
+ if (slot) {
+ if (hotplug) {
+ if ((err = slot->hotplug ? -EBUSY : 0)
+ || (err = rename_slot(slot, name))) {
+ kobject_put(&slot->kobj);
+ slot = NULL;
+ goto err;
+ }
}
+ goto out;
}
placeholder:
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot) {
- slot = ERR_PTR(-ENOMEM);
- goto out;
+ err = -ENOMEM;
+ goto err;
}
slot->bus = parent;
slot->number = slot_nr;
slot->kobj.kset = pci_slots_kset;
- err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
- "%s", name);
- if (err) {
- printk(KERN_ERR "Unable to register kobject %s\n", name);
+
+ slot_name = make_slot_name(name);
+ if (!slot_name) {
+ err = -ENOMEM;
goto err;
}
+ err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
+ "%s", slot_name);
+ if (err)
+ goto err;
+
INIT_LIST_HEAD(&slot->list);
list_add(&slot->list, &parent->slots);
+ list_for_each_entry(dev, &parent->devices, bus_list)
+ if (PCI_SLOT(dev->devfn) == slot_nr)
+ dev->slot = slot;
+
/* Don't care if debug printk has a -1 for slot_nr */
pr_debug("%s: created pci_slot on %04x:%02x:%02x\n",
__func__, pci_domain_nr(parent), parent->number, slot_nr);
- out:
+out:
up_write(&pci_bus_sem);
return slot;
- err:
+err:
kfree(slot);
slot = ERR_PTR(err);
goto out;
@@ -165,7 +263,7 @@ placeholder:
EXPORT_SYMBOL_GPL(pci_create_slot);
/**
- * pci_update_slot_number - update %struct pci_slot -> number
+ * pci_renumber_slot - update %struct pci_slot -> number
* @slot - %struct pci_slot to update
* @slot_nr - new number for slot
*
@@ -173,27 +271,22 @@ EXPORT_SYMBOL_GPL(pci_create_slot);
* created a placeholder slot in pci_create_slot() by passing a -1 as
* slot_nr, to update their %struct pci_slot with the correct @slot_nr.
*/
-
-void pci_update_slot_number(struct pci_slot *slot, int slot_nr)
+void pci_renumber_slot(struct pci_slot *slot, int slot_nr)
{
- int name_count = 0;
struct pci_slot *tmp;
down_write(&pci_bus_sem);
list_for_each_entry(tmp, &slot->bus->slots, list) {
WARN_ON(tmp->number == slot_nr);
- if (!strcmp(kobject_name(&tmp->kobj), kobject_name(&slot->kobj)))
- name_count++;
+ goto out;
}
- if (name_count > 1)
- printk(KERN_WARNING "pci_update_slot_number found %d slots with the same name: %s\n", name_count, kobject_name(&slot->kobj));
-
slot->number = slot_nr;
+out:
up_write(&pci_bus_sem);
}
-EXPORT_SYMBOL_GPL(pci_update_slot_number);
+EXPORT_SYMBOL_GPL(pci_renumber_slot);
/**
* pci_destroy_slot - decrement refcount for physical PCI slot
@@ -203,7 +296,6 @@ EXPORT_SYMBOL_GPL(pci_update_slot_number);
* just call kobject_put on its kobj and let our release methods do the
* rest.
*/
-
void pci_destroy_slot(struct pci_slot *slot)
{
pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__,
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index b46c60b7270..23e492bf75c 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -70,7 +70,7 @@ pxa2xx-obj-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o
pxa2xx-obj-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o
pxa2xx-obj-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x2xx_cs.o
pxa2xx-obj-$(CONFIG_ARCH_VIPER) += pxa2xx_viper.o
-pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA) += pxa2xx_trizeps.o
+pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA) += pxa2xx_trizeps4.o
pxa2xx-obj-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o
pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index a0ffb8ebfe0..9e1140f085f 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -273,7 +273,7 @@ static int __init at91_cf_probe(struct platform_device *pdev)
goto fail0d;
cf->socket.pci_irq = board->irq_pin;
} else
- cf->socket.pci_irq = NR_IRQS + 1;
+ cf->socket.pci_irq = nr_irqs + 1;
/* pcmcia layer only remaps "real" memory not iospace */
cf->socket.io_offset = (unsigned long)
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index 117dc12ab43..9ef69cdb318 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -233,15 +233,18 @@ static struct hw_interrupt_type hd64465_ss_irq_type = {
*/
static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
{
+ struct irq_desc *desc;
+
DPRINTK("hs_map_irq(sock=%d irq=%d)\n", sp->number, irq);
if (irq >= HS_NUM_MAPPED_IRQS)
return;
+ desc = irq_to_desc(irq);
hs_mapped_irq[irq].sock = sp;
/* insert ourselves as the irq controller */
- hs_mapped_irq[irq].old_handler = irq_desc[irq].chip;
- irq_desc[irq].chip = &hd64465_ss_irq_type;
+ hs_mapped_irq[irq].old_handler = desc->chip;
+ desc->chip = &hd64465_ss_irq_type;
}
@@ -250,13 +253,16 @@ static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
*/
static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq)
{
+ struct irq_desc *desc;
+
DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", sp->number, irq);
if (irq >= HS_NUM_MAPPED_IRQS)
return;
+ desc = irq_to_desc(irq);
/* restore the original irq controller */
- irq_desc[irq].chip = hs_mapped_irq[irq].old_handler;
+ desc->chip = hs_mapped_irq[irq].old_handler;
}
/*============================================================*/
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index eee2f1cb213..b2c41241905 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -639,7 +639,7 @@ static int __devinit vrc4171_card_setup(char *options)
int irq;
options += 4;
irq = simple_strtoul(options, &options, 0);
- if (irq >= 0 && irq < NR_IRQS)
+ if (irq >= 0 && irq < nr_irqs)
vrc4171_irq = irq;
if (*options != ',')
diff --git a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig
index 821933f9aa5..2a37b3fedb8 100644
--- a/drivers/pnp/Kconfig
+++ b/drivers/pnp/Kconfig
@@ -20,13 +20,21 @@ menuconfig PNP
If unsure, say Y.
-if PNP
-
-config PNP_DEBUG
- bool "PnP Debug Messages"
+config PNP_DEBUG_MESSAGES
+ default y
+ bool "PNP debugging messages"
+ depends on PNP
help
- Say Y if you want the Plug and Play Layer to print debug messages.
- This is useful if you are developing a PnP driver or troubleshooting.
+ Say Y here if you want the PNP layer to be able to produce debugging
+ messages if needed. The messages can be enabled at boot-time with
+ the pnp.debug kernel parameter.
+
+ This option allows you to save a bit of space if you do not want
+ the messages to even be built into the kernel.
+
+ If you have any doubts about this, say Y here.
+
+if PNP
comment "Protocols"
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile
index e83f34f1b5b..8de3775ec24 100644
--- a/drivers/pnp/Makefile
+++ b/drivers/pnp/Makefile
@@ -10,7 +10,3 @@ obj-$(CONFIG_ISAPNP) += isapnp/
# pnp_system_init goes after pnpacpi/pnpbios init
obj-y += system.o
-
-ifeq ($(CONFIG_PNP_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 3b8b9d3cb03..0b8d14050ef 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -166,3 +166,13 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
resource_size_t start,
resource_size_t end, int flags);
+
+extern int pnp_debug;
+
+#if defined(CONFIG_PNP_DEBUG_MESSAGES)
+#define pnp_dbg(dev, format, arg...) \
+ ({ if (pnp_debug) dev_printk(KERN_DEBUG, dev, format, ## arg); 0; })
+#else
+#define pnp_dbg(dev, format, arg...) \
+ ({ if (0) dev_printk(KERN_DEBUG, dev, format, ## arg); 0; })
+#endif
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 817fe626e15..16c01c6fa7c 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -177,6 +177,9 @@ int __pnp_add_device(struct pnp_dev *dev)
int pnp_add_device(struct pnp_dev *dev)
{
int ret;
+ char buf[128];
+ int len = 0;
+ struct pnp_id *id;
if (dev->card)
return -EINVAL;
@@ -185,17 +188,12 @@ int pnp_add_device(struct pnp_dev *dev)
if (ret)
return ret;
-#ifdef CONFIG_PNP_DEBUG
- {
- struct pnp_id *id;
+ buf[0] = '\0';
+ for (id = dev->id; id; id = id->next)
+ len += scnprintf(buf + len, sizeof(buf) - len, " %s", id->id);
- dev_printk(KERN_DEBUG, &dev->dev, "%s device, IDs",
- dev->protocol->name);
- for (id = dev->id; id; id = id->next)
- printk(" %s", id->id);
- printk(" (%s)\n", dev->active ? "active" : "disabled");
- }
-#endif
+ pnp_dbg(&dev->dev, "%s device, IDs%s (%s)\n",
+ dev->protocol->name, buf, dev->active ? "active" : "disabled");
return 0;
}
@@ -214,3 +212,14 @@ static int __init pnp_init(void)
}
subsys_initcall(pnp_init);
+
+int pnp_debug;
+
+#if defined(CONFIG_PNP_DEBUG_MESSAGES)
+static int __init pnp_debug_setup(char *__unused)
+{
+ pnp_debug = 1;
+ return 1;
+}
+__setup("pnp.debug", pnp_debug_setup);
+#endif
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index e3f7e89c4df..527ee764c93 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -114,7 +114,6 @@ static int pnp_device_probe(struct device *dev)
} else
goto fail;
- dev_dbg(dev, "driver attached\n");
return error;
fail:
@@ -211,8 +210,6 @@ struct bus_type pnp_bus_type = {
int pnp_register_driver(struct pnp_driver *drv)
{
- pnp_dbg("the driver '%s' has been registered", drv->name);
-
drv->driver.name = drv->name;
drv->driver.bus = &pnp_bus_type;
@@ -222,7 +219,6 @@ int pnp_register_driver(struct pnp_driver *drv)
void pnp_unregister_driver(struct pnp_driver *drv)
{
driver_unregister(&drv->driver);
- pnp_dbg("the driver '%s' has been unregistered", drv->name);
}
/**
diff --git a/drivers/pnp/isapnp/Makefile b/drivers/pnp/isapnp/Makefile
index 3e38f06f8d7..cac18bbfb81 100644
--- a/drivers/pnp/isapnp/Makefile
+++ b/drivers/pnp/isapnp/Makefile
@@ -5,7 +5,3 @@
isapnp-proc-$(CONFIG_PROC_FS) = proc.o
obj-y := core.o compat.o $(isapnp-proc-y)
-
-ifeq ($(CONFIG_PNP_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 46455fbab6d..e851160e14f 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -901,7 +901,7 @@ static int isapnp_get_resources(struct pnp_dev *dev)
{
int i, ret;
- dev_dbg(&dev->dev, "get resources\n");
+ pnp_dbg(&dev->dev, "get resources\n");
pnp_init_resources(dev);
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
@@ -939,13 +939,13 @@ static int isapnp_set_resources(struct pnp_dev *dev)
struct resource *res;
int tmp;
- dev_dbg(&dev->dev, "set resources\n");
+ pnp_dbg(&dev->dev, "set resources\n");
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1;
for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) {
res = pnp_get_resource(dev, IORESOURCE_IO, tmp);
if (pnp_resource_enabled(res)) {
- dev_dbg(&dev->dev, " set io %d to %#llx\n",
+ pnp_dbg(&dev->dev, " set io %d to %#llx\n",
tmp, (unsigned long long) res->start);
isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
res->start);
@@ -957,14 +957,14 @@ static int isapnp_set_resources(struct pnp_dev *dev)
int irq = res->start;
if (irq == 2)
irq = 9;
- dev_dbg(&dev->dev, " set irq %d to %d\n", tmp, irq);
+ pnp_dbg(&dev->dev, " set irq %d to %d\n", tmp, irq);
isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
}
}
for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) {
res = pnp_get_resource(dev, IORESOURCE_DMA, tmp);
if (pnp_resource_enabled(res)) {
- dev_dbg(&dev->dev, " set dma %d to %lld\n",
+ pnp_dbg(&dev->dev, " set dma %d to %lld\n",
tmp, (unsigned long long) res->start);
isapnp_write_byte(ISAPNP_CFG_DMA + tmp, res->start);
}
@@ -972,7 +972,7 @@ static int isapnp_set_resources(struct pnp_dev *dev)
for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) {
res = pnp_get_resource(dev, IORESOURCE_MEM, tmp);
if (pnp_resource_enabled(res)) {
- dev_dbg(&dev->dev, " set mem %d to %#llx\n",
+ pnp_dbg(&dev->dev, " set mem %d to %#llx\n",
tmp, (unsigned long long) res->start);
isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3),
(res->start >> 8) & 0xffff);
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index b526eaad3f6..00fd3577b98 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -25,7 +25,7 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
res = pnp_get_resource(dev, IORESOURCE_IO, idx);
if (res) {
- dev_dbg(&dev->dev, " io %d already set to %#llx-%#llx "
+ pnp_dbg(&dev->dev, " io %d already set to %#llx-%#llx "
"flags %#lx\n", idx, (unsigned long long) res->start,
(unsigned long long) res->end, res->flags);
return 0;
@@ -38,7 +38,7 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
if (!rule->size) {
res->flags |= IORESOURCE_DISABLED;
- dev_dbg(&dev->dev, " io %d disabled\n", idx);
+ pnp_dbg(&dev->dev, " io %d disabled\n", idx);
goto __add;
}
@@ -49,7 +49,7 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
res->start += rule->align;
res->end = res->start + rule->size - 1;
if (res->start > rule->max || !rule->align) {
- dev_dbg(&dev->dev, " couldn't assign io %d "
+ pnp_dbg(&dev->dev, " couldn't assign io %d "
"(min %#llx max %#llx)\n", idx,
(unsigned long long) rule->min,
(unsigned long long) rule->max);
@@ -68,7 +68,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
res = pnp_get_resource(dev, IORESOURCE_MEM, idx);
if (res) {
- dev_dbg(&dev->dev, " mem %d already set to %#llx-%#llx "
+ pnp_dbg(&dev->dev, " mem %d already set to %#llx-%#llx "
"flags %#lx\n", idx, (unsigned long long) res->start,
(unsigned long long) res->end, res->flags);
return 0;
@@ -90,7 +90,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
if (!rule->size) {
res->flags |= IORESOURCE_DISABLED;
- dev_dbg(&dev->dev, " mem %d disabled\n", idx);
+ pnp_dbg(&dev->dev, " mem %d disabled\n", idx);
goto __add;
}
@@ -101,7 +101,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
res->start += rule->align;
res->end = res->start + rule->size - 1;
if (res->start > rule->max || !rule->align) {
- dev_dbg(&dev->dev, " couldn't assign mem %d "
+ pnp_dbg(&dev->dev, " couldn't assign mem %d "
"(min %#llx max %#llx)\n", idx,
(unsigned long long) rule->min,
(unsigned long long) rule->max);
@@ -126,7 +126,7 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
res = pnp_get_resource(dev, IORESOURCE_IRQ, idx);
if (res) {
- dev_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n",
+ pnp_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n",
idx, (int) res->start, res->flags);
return 0;
}
@@ -138,7 +138,7 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
res->flags |= IORESOURCE_DISABLED;
- dev_dbg(&dev->dev, " irq %d disabled\n", idx);
+ pnp_dbg(&dev->dev, " irq %d disabled\n", idx);
goto __add;
}
@@ -160,11 +160,11 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
res->start = -1;
res->end = -1;
res->flags |= IORESOURCE_DISABLED;
- dev_dbg(&dev->dev, " irq %d disabled (optional)\n", idx);
+ pnp_dbg(&dev->dev, " irq %d disabled (optional)\n", idx);
goto __add;
}
- dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx);
+ pnp_dbg(&dev->dev, " couldn't assign irq %d\n", idx);
return -EBUSY;
__add:
@@ -184,7 +184,7 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
res = pnp_get_resource(dev, IORESOURCE_DMA, idx);
if (res) {
- dev_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n",
+ pnp_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n",
idx, (int) res->start, res->flags);
return 0;
}
@@ -205,7 +205,7 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
res->start = res->end = MAX_DMA_CHANNELS;
#endif
res->flags |= IORESOURCE_DISABLED;
- dev_dbg(&dev->dev, " disable dma %d\n", idx);
+ pnp_dbg(&dev->dev, " disable dma %d\n", idx);
__add:
pnp_add_dma_resource(dev, res->start, res->flags);
@@ -238,7 +238,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int set)
int nport = 0, nmem = 0, nirq = 0, ndma = 0;
int ret = 0;
- dev_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
+ pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
mutex_lock(&pnp_res_mutex);
pnp_clean_resource_table(dev);
@@ -270,7 +270,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int set)
mutex_unlock(&pnp_res_mutex);
if (ret < 0) {
- dev_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
+ pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
pnp_clean_resource_table(dev);
} else
dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
@@ -286,7 +286,7 @@ int pnp_auto_config_dev(struct pnp_dev *dev)
int i, ret;
if (!pnp_can_configure(dev)) {
- dev_dbg(&dev->dev, "configuration not supported\n");
+ pnp_dbg(&dev->dev, "configuration not supported\n");
return -ENODEV;
}
@@ -313,7 +313,7 @@ int pnp_auto_config_dev(struct pnp_dev *dev)
int pnp_start_dev(struct pnp_dev *dev)
{
if (!pnp_can_write(dev)) {
- dev_dbg(&dev->dev, "activation not supported\n");
+ pnp_dbg(&dev->dev, "activation not supported\n");
return -EINVAL;
}
@@ -336,7 +336,7 @@ int pnp_start_dev(struct pnp_dev *dev)
int pnp_stop_dev(struct pnp_dev *dev)
{
if (!pnp_can_disable(dev)) {
- dev_dbg(&dev->dev, "disabling not supported\n");
+ pnp_dbg(&dev->dev, "disabling not supported\n");
return -EINVAL;
}
if (dev->protocol->disable(dev) < 0) {
diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile
index 2d7a1e6908b..905326fcca8 100644
--- a/drivers/pnp/pnpacpi/Makefile
+++ b/drivers/pnp/pnpacpi/Makefile
@@ -3,7 +3,3 @@
#
obj-y := core.o rsparser.o
-
-ifeq ($(CONFIG_PNP_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 53561d72b4e..383e47c392a 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -75,7 +75,7 @@ static int __init ispnpidacpi(char *id)
static int pnpacpi_get_resources(struct pnp_dev *dev)
{
- dev_dbg(&dev->dev, "get resources\n");
+ pnp_dbg(&dev->dev, "get resources\n");
return pnpacpi_parse_allocated_resource(dev);
}
@@ -86,7 +86,7 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
int ret;
acpi_status status;
- dev_dbg(&dev->dev, "set resources\n");
+ pnp_dbg(&dev->dev, "set resources\n");
ret = pnpacpi_build_resource_template(dev, &buffer);
if (ret)
return ret;
@@ -148,9 +148,13 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
acpi_status status;
struct pnp_dev *dev;
+ /*
+ * If a PnPacpi device is not present , the device
+ * driver should not be loaded.
+ */
status = acpi_get_handle(device->handle, "_CRS", &temp);
if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) ||
- is_exclusive_device(device))
+ is_exclusive_device(device) || (!device->status.present))
return 0;
dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device));
@@ -255,14 +259,14 @@ int pnpacpi_disabled __initdata;
static int __init pnpacpi_init(void)
{
if (acpi_disabled || pnpacpi_disabled) {
- pnp_info("PnP ACPI: disabled");
+ printk(KERN_INFO "pnp: PnP ACPI: disabled\n");
return 0;
}
- pnp_info("PnP ACPI init");
+ printk(KERN_INFO "pnp: PnP ACPI init\n");
pnp_register_protocol(&pnpacpi_protocol);
register_acpi_bus_type(&acpi_pnp_bus);
acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
- pnp_info("PnP ACPI: found %d devices", num);
+ printk(KERN_INFO "pnp: PnP ACPI: found %d devices\n", num);
unregister_acpi_bus_type(&acpi_pnp_bus);
pnp_platform_devices = 1;
return 0;
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 95015cbfd33..adf17856bac 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -132,7 +132,8 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
pnp_add_irq_resource(dev, irq, flags);
}
-static int dma_flags(int type, int bus_master, int transfer)
+static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
+ int transfer)
{
int flags = 0;
@@ -154,7 +155,7 @@ static int dma_flags(int type, int bus_master, int transfer)
default:
/* Set a default value ? */
flags |= IORESOURCE_DMA_COMPATIBLE;
- pnp_err("Invalid DMA type");
+ dev_err(&dev->dev, "invalid DMA type %d\n", type);
}
switch (transfer) {
case ACPI_TRANSFER_8:
@@ -169,7 +170,7 @@ static int dma_flags(int type, int bus_master, int transfer)
default:
/* Set a default value ? */
flags |= IORESOURCE_DMA_8AND16BIT;
- pnp_err("Invalid DMA transfer type");
+ dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer);
}
return flags;
@@ -336,7 +337,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
case ACPI_RESOURCE_TYPE_DMA:
dma = &res->data.dma;
if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
- flags = dma_flags(dma->type, dma->bus_master,
+ flags = dma_flags(dev, dma->type, dma->bus_master,
dma->transfer);
else
flags = IORESOURCE_DISABLED;
@@ -449,7 +450,7 @@ int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
acpi_handle handle = dev->data;
acpi_status status;
- dev_dbg(&dev->dev, "parse allocated resources\n");
+ pnp_dbg(&dev->dev, "parse allocated resources\n");
pnp_init_resources(dev);
@@ -477,7 +478,7 @@ static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
for (i = 0; i < p->channel_count; i++)
map |= 1 << p->channels[i];
- flags = dma_flags(p->type, p->bus_master, p->transfer);
+ flags = dma_flags(dev, p->type, p->bus_master, p->transfer);
pnp_register_dma_resource(dev, option_flags, map, flags);
}
@@ -608,8 +609,8 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
unsigned char flags = 0;
status = acpi_resource_to_address64(r, p);
- if (!ACPI_SUCCESS(status)) {
- pnp_warn("PnPACPI: failed to convert resource type %d",
+ if (ACPI_FAILURE(status)) {
+ dev_warn(&dev->dev, "can't convert resource type %d\n",
r->type);
return;
}
@@ -735,7 +736,7 @@ int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
acpi_status status;
struct acpipnp_parse_option_s parse_data;
- dev_dbg(&dev->dev, "parse resource options\n");
+ pnp_dbg(&dev->dev, "parse resource options\n");
parse_data.dev = dev;
parse_data.option_flags = 0;
@@ -843,7 +844,7 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev,
if (!pnp_resource_enabled(p)) {
irq->interrupt_count = 0;
- dev_dbg(&dev->dev, " encode irq (%s)\n",
+ pnp_dbg(&dev->dev, " encode irq (%s)\n",
p ? "disabled" : "missing");
return;
}
@@ -855,7 +856,7 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev,
irq->interrupt_count = 1;
irq->interrupts[0] = p->start;
- dev_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n",
+ pnp_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n",
(int) p->start,
triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
polarity == ACPI_ACTIVE_LOW ? "low" : "high",
@@ -872,7 +873,7 @@ static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
if (!pnp_resource_enabled(p)) {
extended_irq->interrupt_count = 0;
- dev_dbg(&dev->dev, " encode extended irq (%s)\n",
+ pnp_dbg(&dev->dev, " encode extended irq (%s)\n",
p ? "disabled" : "missing");
return;
}
@@ -885,7 +886,7 @@ static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
extended_irq->interrupt_count = 1;
extended_irq->interrupts[0] = p->start;
- dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start,
+ pnp_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start,
triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
polarity == ACPI_ACTIVE_LOW ? "low" : "high",
extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
@@ -899,7 +900,7 @@ static void pnpacpi_encode_dma(struct pnp_dev *dev,
if (!pnp_resource_enabled(p)) {
dma->channel_count = 0;
- dev_dbg(&dev->dev, " encode dma (%s)\n",
+ pnp_dbg(&dev->dev, " encode dma (%s)\n",
p ? "disabled" : "missing");
return;
}
@@ -934,7 +935,7 @@ static void pnpacpi_encode_dma(struct pnp_dev *dev,
dma->channel_count = 1;
dma->channels[0] = p->start;
- dev_dbg(&dev->dev, " encode dma %d "
+ pnp_dbg(&dev->dev, " encode dma %d "
"type %#x transfer %#x master %d\n",
(int) p->start, dma->type, dma->transfer, dma->bus_master);
}
@@ -958,7 +959,7 @@ static void pnpacpi_encode_io(struct pnp_dev *dev,
io->address_length = 0;
}
- dev_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum,
+ pnp_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum,
io->minimum + io->address_length - 1, io->io_decode);
}
@@ -976,7 +977,7 @@ static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
fixed_io->address_length = 0;
}
- dev_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address,
+ pnp_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address,
fixed_io->address + fixed_io->address_length - 1);
}
@@ -999,7 +1000,7 @@ static void pnpacpi_encode_mem24(struct pnp_dev *dev,
memory24->address_length = 0;
}
- dev_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n",
+ pnp_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n",
memory24->minimum,
memory24->minimum + memory24->address_length - 1,
memory24->write_protect);
@@ -1023,7 +1024,7 @@ static void pnpacpi_encode_mem32(struct pnp_dev *dev,
memory32->alignment = 0;
}
- dev_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n",
+ pnp_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n",
memory32->minimum,
memory32->minimum + memory32->address_length - 1,
memory32->write_protect);
@@ -1046,7 +1047,7 @@ static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
fixed_memory32->address_length = 0;
}
- dev_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n",
+ pnp_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n",
fixed_memory32->address,
fixed_memory32->address + fixed_memory32->address_length - 1,
fixed_memory32->write_protect);
@@ -1060,7 +1061,7 @@ int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
struct acpi_resource *resource = buffer->pointer;
int port = 0, irq = 0, dma = 0, mem = 0;
- dev_dbg(&dev->dev, "encode %d resources\n", res_cnt);
+ pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt);
while (i < res_cnt) {
switch (resource->type) {
case ACPI_RESOURCE_TYPE_IRQ:
diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile
index 310e2b3a771..3cd3ed76060 100644
--- a/drivers/pnp/pnpbios/Makefile
+++ b/drivers/pnp/pnpbios/Makefile
@@ -5,7 +5,3 @@
pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o
obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y)
-
-ifeq ($(CONFIG_PNP_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 2bfe13369df..996f6483807 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -211,7 +211,7 @@ static int pnpbios_get_resources(struct pnp_dev *dev)
if (!pnpbios_is_dynamic(dev))
return -EPERM;
- dev_dbg(&dev->dev, "get resources\n");
+ pnp_dbg(&dev->dev, "get resources\n");
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
@@ -234,7 +234,7 @@ static int pnpbios_set_resources(struct pnp_dev *dev)
if (!pnpbios_is_dynamic(dev))
return -EPERM;
- dev_dbg(&dev->dev, "set resources\n");
+ pnp_dbg(&dev->dev, "set resources\n");
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index ca567671379..87b4f49a525 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -87,7 +87,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev,
if (!p)
return NULL;
- dev_dbg(&dev->dev, "parse allocated resources\n");
+ pnp_dbg(&dev->dev, "parse allocated resources\n");
pnp_init_resources(dev);
@@ -324,7 +324,7 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
if (!p)
return NULL;
- dev_dbg(&dev->dev, "parse resource options\n");
+ pnp_dbg(&dev->dev, "parse resource options\n");
option_flags = 0;
while ((char *)p < (char *)end) {
@@ -519,7 +519,7 @@ static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p,
p[10] = (len >> 8) & 0xff;
p[11] = ((len >> 8) >> 8) & 0xff;
- dev_dbg(&dev->dev, " encode mem %#lx-%#lx\n", base, base + len - 1);
+ pnp_dbg(&dev->dev, " encode mem %#lx-%#lx\n", base, base + len - 1);
}
static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p,
@@ -549,7 +549,7 @@ static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p,
p[18] = (len >> 16) & 0xff;
p[19] = (len >> 24) & 0xff;
- dev_dbg(&dev->dev, " encode mem32 %#lx-%#lx\n", base, base + len - 1);
+ pnp_dbg(&dev->dev, " encode mem32 %#lx-%#lx\n", base, base + len - 1);
}
static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p,
@@ -575,7 +575,7 @@ static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p,
p[10] = (len >> 16) & 0xff;
p[11] = (len >> 24) & 0xff;
- dev_dbg(&dev->dev, " encode fixed_mem32 %#lx-%#lx\n", base,
+ pnp_dbg(&dev->dev, " encode fixed_mem32 %#lx-%#lx\n", base,
base + len - 1);
}
@@ -592,7 +592,7 @@ static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p,
p[1] = map & 0xff;
p[2] = (map >> 8) & 0xff;
- dev_dbg(&dev->dev, " encode irq mask %#lx\n", map);
+ pnp_dbg(&dev->dev, " encode irq mask %#lx\n", map);
}
static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
@@ -607,7 +607,7 @@ static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
p[1] = map & 0xff;
- dev_dbg(&dev->dev, " encode dma mask %#lx\n", map);
+ pnp_dbg(&dev->dev, " encode dma mask %#lx\n", map);
}
static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
@@ -630,7 +630,7 @@ static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
p[5] = (base >> 8) & 0xff;
p[7] = len & 0xff;
- dev_dbg(&dev->dev, " encode io %#lx-%#lx\n", base, base + len - 1);
+ pnp_dbg(&dev->dev, " encode io %#lx-%#lx\n", base, base + len - 1);
}
static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p,
@@ -651,7 +651,7 @@ static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p,
p[2] = (base >> 8) & 0xff;
p[3] = len & 0xff;
- dev_dbg(&dev->dev, " encode fixed_io %#lx-%#lx\n", base,
+ pnp_dbg(&dev->dev, " encode fixed_io %#lx-%#lx\n", base,
base + len - 1);
}
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index c144bd57561..8473fe5ed7f 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -337,9 +337,8 @@ void pnp_fixup_device(struct pnp_dev *dev)
for (f = pnp_fixups; *f->id; f++) {
if (!compare_pnp_id(dev->id, f->id))
continue;
-#ifdef DEBUG
- dev_dbg(&dev->dev, "%s: calling %pF\n", f->id, f->quirk_function);
-#endif
+ pnp_dbg(&dev->dev, "%s: calling %pF\n", f->id,
+ f->quirk_function);
f->quirk_function(dev);
}
}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index dbae23acdd5..f604061d2bb 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -294,7 +294,7 @@ static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci,
u8 progif;
if (pci->irq == irq) {
- dev_dbg(&pnp->dev, "device %s using irq %d\n",
+ pnp_dbg(&pnp->dev, " device %s using irq %d\n",
pci_name(pci), irq);
return 1;
}
@@ -316,7 +316,7 @@ static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci,
if ((progif & 0x5) != 0x5)
if (pci_get_legacy_ide_irq(pci, 0) == irq ||
pci_get_legacy_ide_irq(pci, 1) == irq) {
- dev_dbg(&pnp->dev, "legacy IDE device %s "
+ pnp_dbg(&pnp->dev, " legacy IDE device %s "
"using irq %d\n", pci_name(pci), irq);
return 1;
}
@@ -517,7 +517,7 @@ struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
res->start = irq;
res->end = irq;
- dev_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags);
+ pnp_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags);
return pnp_res;
}
@@ -538,7 +538,7 @@ struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
res->start = dma;
res->end = dma;
- dev_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags);
+ pnp_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags);
return pnp_res;
}
@@ -562,7 +562,7 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
res->start = start;
res->end = end;
- dev_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n",
+ pnp_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n",
(unsigned long long) start, (unsigned long long) end, flags);
return pnp_res;
}
@@ -587,7 +587,7 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
res->start = start;
res->end = end;
- dev_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n",
+ pnp_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n",
(unsigned long long) start, (unsigned long long) end, flags);
return pnp_res;
}
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index b42df162071..63087d5ce60 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -75,18 +75,17 @@ char *pnp_resource_type_name(struct resource *res)
void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc)
{
-#ifdef DEBUG
char buf[128];
int len;
struct pnp_resource *pnp_res;
struct resource *res;
if (list_empty(&dev->resources)) {
- dev_dbg(&dev->dev, "%s: no current resources\n", desc);
+ pnp_dbg(&dev->dev, "%s: no current resources\n", desc);
return;
}
- dev_dbg(&dev->dev, "%s: current resources:\n", desc);
+ pnp_dbg(&dev->dev, "%s: current resources:\n", desc);
list_for_each_entry(pnp_res, &dev->resources, list) {
res = &pnp_res->res;
len = 0;
@@ -95,7 +94,7 @@ void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc)
pnp_resource_type_name(res));
if (res->flags & IORESOURCE_DISABLED) {
- dev_dbg(&dev->dev, "%sdisabled\n", buf);
+ pnp_dbg(&dev->dev, "%sdisabled\n", buf);
continue;
}
@@ -116,9 +115,8 @@ void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc)
res->flags);
break;
}
- dev_dbg(&dev->dev, "%s\n", buf);
+ pnp_dbg(&dev->dev, "%s\n", buf);
}
-#endif
}
char *pnp_option_priority_name(struct pnp_option *option)
@@ -136,7 +134,6 @@ char *pnp_option_priority_name(struct pnp_option *option)
void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option)
{
-#ifdef DEBUG
char buf[128];
int len = 0, i;
struct pnp_port *port;
@@ -208,6 +205,5 @@ void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option)
"flags %#x", dma->map, dma->flags);
break;
}
- dev_dbg(&dev->dev, "%s\n", buf);
-#endif
+ pnp_dbg(&dev->dev, "%s\n", buf);
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 63bb5791044..8e0c2b47803 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -51,7 +51,7 @@ config BATTERY_OLPC
config BATTERY_TOSA
tristate "Sharp SL-6000 (tosa) battery"
- depends on MACH_TOSA && MFD_TC6393XB
+ depends on MACH_TOSA && MFD_TC6393XB && TOUCHSCREEN_WM97XX
help
Say Y to enable support for the battery on the Sharp Zaurus
SL-6000 (tosa) models.
@@ -62,4 +62,10 @@ config BATTERY_WM97XX
help
Say Y to enable support for battery measured by WM97xx aux port.
+config BATTERY_BQ27x00
+ tristate "BQ27200 battery driver"
+ depends on I2C
+ help
+ Say Y here to enable support for batteries with BQ27200(I2C) chip.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 4e20026cc45..e8f1ecec5d8 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
-obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o \ No newline at end of file
+obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
+obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
new file mode 100644
index 00000000000..0c056fcc01c
--- /dev/null
+++ b/drivers/power/bq27x00_battery.c
@@ -0,0 +1,381 @@
+/*
+ * BQ27x00 battery driver
+ *
+ * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/idr.h>
+#include <linux/i2c.h>
+#include <asm/unaligned.h>
+
+#define DRIVER_VERSION "1.0.0"
+
+#define BQ27x00_REG_TEMP 0x06
+#define BQ27x00_REG_VOLT 0x08
+#define BQ27x00_REG_RSOC 0x0B /* Relative State-of-Charge */
+#define BQ27x00_REG_AI 0x14
+#define BQ27x00_REG_FLAGS 0x0A
+
+/* If the system has several batteries we need a different name for each
+ * of them...
+ */
+static DEFINE_IDR(battery_id);
+static DEFINE_MUTEX(battery_mutex);
+
+struct bq27x00_device_info;
+struct bq27x00_access_methods {
+ int (*read)(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di);
+};
+
+struct bq27x00_device_info {
+ struct device *dev;
+ int id;
+ int voltage_uV;
+ int current_uA;
+ int temp_C;
+ int charge_rsoc;
+ struct bq27x00_access_methods *bus;
+ struct power_supply bat;
+
+ struct i2c_client *client;
+};
+
+static enum power_supply_property bq27x00_battery_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_TEMP,
+};
+
+/*
+ * Common code for BQ27x00 devices
+ */
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di)
+{
+ int ret;
+
+ ret = di->bus->read(reg, rt_value, b_single, di);
+ *rt_value = be16_to_cpu(*rt_value);
+
+ return ret;
+}
+
+/*
+ * Return the battery temperature in Celcius degrees
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
+{
+ int ret;
+ int temp = 0;
+
+ ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
+ if (ret) {
+ dev_err(di->dev, "error reading temperature\n");
+ return ret;
+ }
+
+ return (temp >> 2) - 273;
+}
+
+/*
+ * Return the battery Voltage in milivolts
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
+{
+ int ret;
+ int volt = 0;
+
+ ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
+ if (ret) {
+ dev_err(di->dev, "error reading voltage\n");
+ return ret;
+ }
+
+ return volt;
+}
+
+/*
+ * Return the battery average current
+ * Note that current can be negative signed as well
+ * Or 0 if something fails.
+ */
+static int bq27x00_battery_current(struct bq27x00_device_info *di)
+{
+ int ret;
+ int curr = 0;
+ int flags = 0;
+
+ ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
+ if (ret) {
+ dev_err(di->dev, "error reading current\n");
+ return 0;
+ }
+ ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+ if (ret < 0) {
+ dev_err(di->dev, "error reading flags\n");
+ return 0;
+ }
+ if ((flags & (1 << 7)) != 0) {
+ dev_dbg(di->dev, "negative current!\n");
+ return -curr;
+ }
+ return curr;
+}
+
+/*
+ * Return the battery Relative State-of-Charge
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
+{
+ int ret;
+ int rsoc = 0;
+
+ ret = bq27x00_read(BQ27x00_REG_RSOC, &rsoc, 1, di);
+ if (ret) {
+ dev_err(di->dev, "error reading relative State-of-Charge\n");
+ return ret;
+ }
+
+ return rsoc >> 8;
+}
+
+#define to_bq27x00_device_info(x) container_of((x), \
+ struct bq27x00_device_info, bat);
+
+static int bq27x00_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = bq27x00_battery_voltage(di);
+ if (psp == POWER_SUPPLY_PROP_PRESENT)
+ val->intval = val->intval <= 0 ? 0 : 1;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = bq27x00_battery_current(di);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = bq27x00_battery_rsoc(di);
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = bq27x00_battery_temperature(di);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
+{
+ di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ di->bat.properties = bq27x00_battery_props;
+ di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
+ di->bat.get_property = bq27x00_battery_get_property;
+ di->bat.external_power_changed = NULL;
+}
+
+/*
+ * BQ27200 specific code
+ */
+
+static int bq27200_read(u8 reg, int *rt_value, int b_single,
+ struct bq27x00_device_info *di)
+{
+ struct i2c_client *client = di->client;
+ struct i2c_msg msg[1];
+ unsigned char data[2];
+ int err;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = 1;
+ msg->buf = data;
+
+ data[0] = reg;
+ err = i2c_transfer(client->adapter, msg, 1);
+
+ if (err >= 0) {
+ if (!b_single)
+ msg->len = 2;
+ else
+ msg->len = 1;
+
+ msg->flags = I2C_M_RD;
+ err = i2c_transfer(client->adapter, msg, 1);
+ if (err >= 0) {
+ if (!b_single)
+ *rt_value = get_unaligned_be16(data);
+ else
+ *rt_value = data[0];
+
+ return 0;
+ }
+ }
+ return err;
+}
+
+static int bq27200_battery_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ char *name;
+ struct bq27x00_device_info *di;
+ struct bq27x00_access_methods *bus;
+ int num;
+ int retval = 0;
+
+ /* Get new ID for the new battery device */
+ retval = idr_pre_get(&battery_id, GFP_KERNEL);
+ if (retval == 0)
+ return -ENOMEM;
+ mutex_lock(&battery_mutex);
+ retval = idr_get_new(&battery_id, client, &num);
+ mutex_unlock(&battery_mutex);
+ if (retval < 0)
+ return retval;
+
+ name = kasprintf(GFP_KERNEL, "bq27200-%d", num);
+ if (!name) {
+ dev_err(&client->dev, "failed to allocate device name\n");
+ retval = -ENOMEM;
+ goto batt_failed_1;
+ }
+
+ di = kzalloc(sizeof(*di), GFP_KERNEL);
+ if (!di) {
+ dev_err(&client->dev, "failed to allocate device info data\n");
+ retval = -ENOMEM;
+ goto batt_failed_2;
+ }
+ di->id = num;
+
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (!bus) {
+ dev_err(&client->dev, "failed to allocate access method "
+ "data\n");
+ retval = -ENOMEM;
+ goto batt_failed_3;
+ }
+
+ i2c_set_clientdata(client, di);
+ di->dev = &client->dev;
+ di->bat.name = name;
+ bus->read = &bq27200_read;
+ di->bus = bus;
+ di->client = client;
+
+ bq27x00_powersupply_init(di);
+
+ retval = power_supply_register(&client->dev, &di->bat);
+ if (retval) {
+ dev_err(&client->dev, "failed to register battery\n");
+ goto batt_failed_4;
+ }
+
+ dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
+
+ return 0;
+
+batt_failed_4:
+ kfree(bus);
+batt_failed_3:
+ kfree(di);
+batt_failed_2:
+ kfree(name);
+batt_failed_1:
+ mutex_lock(&battery_mutex);
+ idr_remove(&battery_id, num);
+ mutex_unlock(&battery_mutex);
+
+ return retval;
+}
+
+static int bq27200_battery_remove(struct i2c_client *client)
+{
+ struct bq27x00_device_info *di = i2c_get_clientdata(client);
+
+ power_supply_unregister(&di->bat);
+
+ kfree(di->bat.name);
+
+ mutex_lock(&battery_mutex);
+ idr_remove(&battery_id, di->id);
+ mutex_unlock(&battery_mutex);
+
+ kfree(di);
+
+ return 0;
+}
+
+/*
+ * Module stuff
+ */
+
+static const struct i2c_device_id bq27200_id[] = {
+ { "bq27200", 0 },
+ {},
+};
+
+static struct i2c_driver bq27200_battery_driver = {
+ .driver = {
+ .name = "bq27200-battery",
+ },
+ .probe = bq27200_battery_probe,
+ .remove = bq27200_battery_remove,
+ .id_table = bq27200_id,
+};
+
+static int __init bq27x00_battery_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&bq27200_battery_driver);
+ if (ret)
+ printk(KERN_ERR "Unable to register BQ27200 driver\n");
+
+ return ret;
+}
+module_init(bq27x00_battery_init);
+
+static void __exit bq27x00_battery_exit(void)
+{
+ i2c_del_driver(&bq27200_battery_driver);
+}
+module_exit(bq27x00_battery_exit);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("BQ27x00 battery monitor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index 0471ec743ab..d30bb766fce 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -334,13 +334,16 @@ static int pda_power_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
+static int ac_wakeup_enabled;
+static int usb_wakeup_enabled;
+
static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
{
if (device_may_wakeup(&pdev->dev)) {
if (ac_irq)
- enable_irq_wake(ac_irq->start);
+ ac_wakeup_enabled = !enable_irq_wake(ac_irq->start);
if (usb_irq)
- enable_irq_wake(usb_irq->start);
+ usb_wakeup_enabled = !enable_irq_wake(usb_irq->start);
}
return 0;
@@ -349,9 +352,9 @@ static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
static int pda_power_resume(struct platform_device *pdev)
{
if (device_may_wakeup(&pdev->dev)) {
- if (usb_irq)
+ if (usb_irq && usb_wakeup_enabled)
disable_irq_wake(usb_irq->start);
- if (ac_irq)
+ if (ac_irq && ac_wakeup_enabled)
disable_irq_wake(ac_irq->start);
}
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 3007695f90c..5520040449c 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -87,6 +87,30 @@ int power_supply_am_i_supplied(struct power_supply *psy)
return error;
}
+static int __power_supply_is_system_supplied(struct device *dev, void *data)
+{
+ union power_supply_propval ret = {0,};
+ struct power_supply *psy = dev_get_drvdata(dev);
+
+ if (psy->type != POWER_SUPPLY_TYPE_BATTERY) {
+ if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
+ return 0;
+ if (ret.intval)
+ return ret.intval;
+ }
+ return 0;
+}
+
+int power_supply_is_system_supplied(void)
+{
+ int error;
+
+ error = class_for_each_device(power_supply_class, NULL, NULL,
+ __power_supply_is_system_supplied);
+
+ return error;
+}
+
int power_supply_register(struct device *parent, struct power_supply *psy)
{
int rc = 0;
@@ -148,6 +172,7 @@ static void __exit power_supply_class_exit(void)
EXPORT_SYMBOL_GPL(power_supply_changed);
EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
+EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
EXPORT_SYMBOL_GPL(power_supply_register);
EXPORT_SYMBOL_GPL(power_supply_unregister);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index fe2aeb11939..23ae8460f5c 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -30,7 +30,7 @@
#define POWER_SUPPLY_ATTR(_name) \
{ \
- .attr = { .name = #_name, .mode = 0444, .owner = THIS_MODULE }, \
+ .attr = { .name = #_name, .mode = 0444 }, \
.show = power_supply_show_property, \
.store = NULL, \
}
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index 6f2f90ebb02..06848b254d5 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -915,6 +915,22 @@ int ps3av_video_mute(int mute)
EXPORT_SYMBOL_GPL(ps3av_video_mute);
+/* mute analog output only */
+int ps3av_audio_mute_analog(int mute)
+{
+ int i, res;
+
+ for (i = 0; i < ps3av->av_hw_conf.num_of_avmulti; i++) {
+ res = ps3av_cmd_av_audio_mute(1,
+ &ps3av->av_port[i + ps3av->av_hw_conf.num_of_hdmi],
+ mute);
+ if (res < 0)
+ return -1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3av_audio_mute_analog);
+
int ps3av_audio_mute(int mute)
{
return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
index 7f880c26122..11eb50318fe 100644
--- a/drivers/ps3/ps3av_cmd.c
+++ b/drivers/ps3/ps3av_cmd.c
@@ -660,9 +660,10 @@ u32 ps3av_cmd_set_av_audio_param(void *p, u32 port,
}
/* default cs val */
-static const u8 ps3av_mode_cs_info[] = {
+u8 ps3av_mode_cs_info[] = {
0x00, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00
};
+EXPORT_SYMBOL_GPL(ps3av_mode_cs_info);
#define CS_44 0x00
#define CS_48 0x02
@@ -677,7 +678,7 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,
u32 ch, u32 fs, u32 word_bits, u32 format,
u32 source)
{
- int spdif_through, spdif_bitstream;
+ int spdif_through;
int i;
if (!(ch | fs | format | word_bits | source)) {
@@ -687,7 +688,6 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,
format = PS3AV_CMD_AUDIO_FORMAT_PCM;
source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
}
- spdif_through = spdif_bitstream = 0; /* XXX not supported */
/* audio mode */
memset(audio, 0, sizeof(*audio));
@@ -777,16 +777,17 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,
break;
}
+ /* non-audio bit */
+ spdif_through = audio->audio_cs_info[0] & 0x02;
+
/* pass through setting */
if (spdif_through &&
(avport == PS3AV_CMD_AVPORT_SPDIF_0 ||
- avport == PS3AV_CMD_AVPORT_SPDIF_1)) {
+ avport == PS3AV_CMD_AVPORT_SPDIF_1 ||
+ avport == PS3AV_CMD_AVPORT_HDMI_0 ||
+ avport == PS3AV_CMD_AVPORT_HDMI_1)) {
audio->audio_word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16;
- audio->audio_source = PS3AV_CMD_AUDIO_SOURCE_SPDIF;
- if (spdif_bitstream) {
- audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM;
- audio->audio_cs_info[0] |= CS_BIT;
- }
+ audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM;
}
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index f660ef3e5b2..8abbb2020af 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -171,10 +171,10 @@ config RTC_DRV_MAX6900
will be called rtc-max6900.
config RTC_DRV_RS5C372
- tristate "Ricoh RS5C372A/B, RV5C386, RV5C387A"
+ tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
help
If you say yes here you get support for the
- Ricoh RS5C372A, RS5C372B, RV5C386, and RV5C387A RTC chips.
+ Ricoh R2025S/D, RS5C372A, RS5C372B, RV5C386, and RV5C387A RTC chips.
This driver can also be built as a module. If so, the module
will be called rtc-rs5c372.
@@ -246,6 +246,16 @@ config RTC_DRV_TWL92330
platforms. The support is integrated with the rest of
the Menelaus driver; it's not separate module.
+config RTC_DRV_TWL4030
+ tristate "TI TWL4030/TWL5030/TPS659x0"
+ depends on RTC_CLASS && TWL4030_CORE
+ help
+ If you say yes here you get support for the RTC on the
+ TWL4030 family chips, used mostly with OMAP3 platforms.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-twl4030.
+
config RTC_DRV_S35390A
tristate "Seiko Instruments S-35390A"
select BITREVERSE
@@ -610,6 +620,14 @@ config RTC_DRV_RS5C313
help
If you say yes here you get support for the Ricoh RS5C313 RTC chips.
+config RTC_DRV_PARISC
+ tristate "PA-RISC firmware RTC support"
+ depends on PARISC
+ help
+ Say Y or M here to enable RTC support on PA-RISC systems using
+ firmware calls. If you do not know what you are doing, you should
+ just say Y.
+
config RTC_DRV_PPC
tristate "PowerPC machine dependent RTC support"
depends on PPC
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index d05928b3ca9..e9e8474cc8f 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_PARISC) += rtc-parisc.o
obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
@@ -62,6 +63,7 @@ obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
+obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index 37082616482..b5bf9370691 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -53,21 +53,21 @@ static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
} while ((time != at91_sys_read(timereg)) ||
(date != at91_sys_read(calreg)));
- tm->tm_sec = BCD2BIN((time & AT91_RTC_SEC) >> 0);
- tm->tm_min = BCD2BIN((time & AT91_RTC_MIN) >> 8);
- tm->tm_hour = BCD2BIN((time & AT91_RTC_HOUR) >> 16);
+ tm->tm_sec = bcd2bin((time & AT91_RTC_SEC) >> 0);
+ tm->tm_min = bcd2bin((time & AT91_RTC_MIN) >> 8);
+ tm->tm_hour = bcd2bin((time & AT91_RTC_HOUR) >> 16);
/*
* The Calendar Alarm register does not have a field for
* the year - so these will return an invalid value. When an
* alarm is set, at91_alarm_year wille store the current year.
*/
- tm->tm_year = BCD2BIN(date & AT91_RTC_CENT) * 100; /* century */
- tm->tm_year += BCD2BIN((date & AT91_RTC_YEAR) >> 8); /* year */
+ tm->tm_year = bcd2bin(date & AT91_RTC_CENT) * 100; /* century */
+ tm->tm_year += bcd2bin((date & AT91_RTC_YEAR) >> 8); /* year */
- tm->tm_wday = BCD2BIN((date & AT91_RTC_DAY) >> 21) - 1; /* day of the week [0-6], Sunday=0 */
- tm->tm_mon = BCD2BIN((date & AT91_RTC_MONTH) >> 16) - 1;
- tm->tm_mday = BCD2BIN((date & AT91_RTC_DATE) >> 24);
+ tm->tm_wday = bcd2bin((date & AT91_RTC_DAY) >> 21) - 1; /* day of the week [0-6], Sunday=0 */
+ tm->tm_mon = bcd2bin((date & AT91_RTC_MONTH) >> 16) - 1;
+ tm->tm_mday = bcd2bin((date & AT91_RTC_DATE) >> 24);
}
/*
@@ -106,16 +106,16 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
at91_sys_write(AT91_RTC_TIMR,
- BIN2BCD(tm->tm_sec) << 0
- | BIN2BCD(tm->tm_min) << 8
- | BIN2BCD(tm->tm_hour) << 16);
+ bin2bcd(tm->tm_sec) << 0
+ | bin2bcd(tm->tm_min) << 8
+ | bin2bcd(tm->tm_hour) << 16);
at91_sys_write(AT91_RTC_CALR,
- BIN2BCD((tm->tm_year + 1900) / 100) /* century */
- | BIN2BCD(tm->tm_year % 100) << 8 /* year */
- | BIN2BCD(tm->tm_mon + 1) << 16 /* tm_mon starts at zero */
- | BIN2BCD(tm->tm_wday + 1) << 21 /* day of the week [0-6], Sunday=0 */
- | BIN2BCD(tm->tm_mday) << 24);
+ bin2bcd((tm->tm_year + 1900) / 100) /* century */
+ | bin2bcd(tm->tm_year % 100) << 8 /* year */
+ | bin2bcd(tm->tm_mon + 1) << 16 /* tm_mon starts at zero */
+ | bin2bcd(tm->tm_wday + 1) << 21 /* day of the week [0-6], Sunday=0 */
+ | bin2bcd(tm->tm_mday) << 24);
/* Restart Time/Calendar */
cr = at91_sys_read(AT91_RTC_CR);
@@ -162,13 +162,13 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
at91_sys_write(AT91_RTC_TIMALR,
- BIN2BCD(tm.tm_sec) << 0
- | BIN2BCD(tm.tm_min) << 8
- | BIN2BCD(tm.tm_hour) << 16
+ bin2bcd(tm.tm_sec) << 0
+ | bin2bcd(tm.tm_min) << 8
+ | bin2bcd(tm.tm_hour) << 16
| AT91_RTC_HOUREN | AT91_RTC_MINEN | AT91_RTC_SECEN);
at91_sys_write(AT91_RTC_CALALR,
- BIN2BCD(tm.tm_mon + 1) << 16 /* tm_mon starts at zero */
- | BIN2BCD(tm.tm_mday) << 24
+ bin2bcd(tm.tm_mon + 1) << 16 /* tm_mon starts at zero */
+ | bin2bcd(tm.tm_mday) << 24
| AT91_RTC_DATEEN | AT91_RTC_MTHEN);
if (alrm->enabled) {
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
index 189a018bdf3..d00a274df8f 100644
--- a/drivers/rtc/rtc-bq4802.c
+++ b/drivers/rtc/rtc-bq4802.c
@@ -71,14 +71,14 @@ static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
spin_unlock_irqrestore(&p->lock, flags);
- BCD_TO_BIN(tm->tm_sec);
- BCD_TO_BIN(tm->tm_min);
- BCD_TO_BIN(tm->tm_hour);
- BCD_TO_BIN(tm->tm_mday);
- BCD_TO_BIN(tm->tm_mon);
- BCD_TO_BIN(tm->tm_year);
- BCD_TO_BIN(tm->tm_wday);
- BCD_TO_BIN(century);
+ tm->tm_sec = bcd2bin(tm->tm_sec);
+ tm->tm_min = bcd2bin(tm->tm_min);
+ tm->tm_hour = bcd2bin(tm->tm_hour);
+ tm->tm_mday = bcd2bin(tm->tm_mday);
+ tm->tm_mon = bcd2bin(tm->tm_mon);
+ tm->tm_year = bcd2bin(tm->tm_year);
+ tm->tm_wday = bcd2bin(tm->tm_wday);
+ century = bcd2bin(century);
tm->tm_year += (century * 100);
tm->tm_year -= 1900;
@@ -106,13 +106,13 @@ static int bq4802_set_time(struct device *dev, struct rtc_time *tm)
min = tm->tm_min;
sec = tm->tm_sec;
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hrs);
- BIN_TO_BCD(day);
- BIN_TO_BCD(mon);
- BIN_TO_BCD(yrs);
- BIN_TO_BCD(century);
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hrs = bin2bcd(hrs);
+ day = bin2bcd(day);
+ mon = bin2bcd(mon);
+ yrs = bin2bcd(yrs);
+ century = bin2bcd(century);
spin_lock_irqsave(&p->lock, flags);
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 963ad0b6a4e..5549231179a 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -143,6 +143,43 @@ static inline int hpet_unregister_irq_handler(irq_handler_t handler)
/*----------------------------------------------------------------*/
+#ifdef RTC_PORT
+
+/* Most newer x86 systems have two register banks, the first used
+ * for RTC and NVRAM and the second only for NVRAM. Caller must
+ * own rtc_lock ... and we won't worry about access during NMI.
+ */
+#define can_bank2 true
+
+static inline unsigned char cmos_read_bank2(unsigned char addr)
+{
+ outb(addr, RTC_PORT(2));
+ return inb(RTC_PORT(3));
+}
+
+static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
+{
+ outb(addr, RTC_PORT(2));
+ outb(val, RTC_PORT(2));
+}
+
+#else
+
+#define can_bank2 false
+
+static inline unsigned char cmos_read_bank2(unsigned char addr)
+{
+ return 0;
+}
+
+static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
+{
+}
+
+#endif
+
+/*----------------------------------------------------------------*/
+
static int cmos_read_time(struct device *dev, struct rtc_time *t)
{
/* REVISIT: if the clock has a "century" register, use
@@ -203,26 +240,26 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
/* REVISIT this assumes PC style usage: always BCD */
if (((unsigned)t->time.tm_sec) < 0x60)
- t->time.tm_sec = BCD2BIN(t->time.tm_sec);
+ t->time.tm_sec = bcd2bin(t->time.tm_sec);
else
t->time.tm_sec = -1;
if (((unsigned)t->time.tm_min) < 0x60)
- t->time.tm_min = BCD2BIN(t->time.tm_min);
+ t->time.tm_min = bcd2bin(t->time.tm_min);
else
t->time.tm_min = -1;
if (((unsigned)t->time.tm_hour) < 0x24)
- t->time.tm_hour = BCD2BIN(t->time.tm_hour);
+ t->time.tm_hour = bcd2bin(t->time.tm_hour);
else
t->time.tm_hour = -1;
if (cmos->day_alrm) {
if (((unsigned)t->time.tm_mday) <= 0x31)
- t->time.tm_mday = BCD2BIN(t->time.tm_mday);
+ t->time.tm_mday = bcd2bin(t->time.tm_mday);
else
t->time.tm_mday = -1;
if (cmos->mon_alrm) {
if (((unsigned)t->time.tm_mon) <= 0x12)
- t->time.tm_mon = BCD2BIN(t->time.tm_mon) - 1;
+ t->time.tm_mon = bcd2bin(t->time.tm_mon) - 1;
else
t->time.tm_mon = -1;
}
@@ -294,19 +331,19 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
/* Writing 0xff means "don't care" or "match all". */
mon = t->time.tm_mon + 1;
- mon = (mon <= 12) ? BIN2BCD(mon) : 0xff;
+ mon = (mon <= 12) ? bin2bcd(mon) : 0xff;
mday = t->time.tm_mday;
- mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff;
+ mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff;
hrs = t->time.tm_hour;
- hrs = (hrs < 24) ? BIN2BCD(hrs) : 0xff;
+ hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff;
min = t->time.tm_min;
- min = (min < 60) ? BIN2BCD(min) : 0xff;
+ min = (min < 60) ? bin2bcd(min) : 0xff;
sec = t->time.tm_sec;
- sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
+ sec = (sec < 60) ? bin2bcd(sec) : 0xff;
spin_lock_irq(&rtc_lock);
@@ -491,12 +528,21 @@ cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
if (unlikely(off >= attr->size))
return 0;
+ if (unlikely(off < 0))
+ return -EINVAL;
if ((off + count) > attr->size)
count = attr->size - off;
+ off += NVRAM_OFFSET;
spin_lock_irq(&rtc_lock);
- for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++)
- *buf++ = CMOS_READ(off);
+ for (retval = 0; count; count--, off++, retval++) {
+ if (off < 128)
+ *buf++ = CMOS_READ(off);
+ else if (can_bank2)
+ *buf++ = cmos_read_bank2(off);
+ else
+ break;
+ }
spin_unlock_irq(&rtc_lock);
return retval;
@@ -512,6 +558,8 @@ cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
if (unlikely(off >= attr->size))
return -EFBIG;
+ if (unlikely(off < 0))
+ return -EINVAL;
if ((off + count) > attr->size)
count = attr->size - off;
@@ -520,15 +568,20 @@ cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
* here. If userspace is smart enough to know what fields of
* NVRAM to update, updating checksums is also part of its job.
*/
+ off += NVRAM_OFFSET;
spin_lock_irq(&rtc_lock);
- for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) {
+ for (retval = 0; count; count--, off++, retval++) {
/* don't trash RTC registers */
if (off == cmos->day_alrm
|| off == cmos->mon_alrm
|| off == cmos->century)
buf++;
- else
+ else if (off < 128)
CMOS_WRITE(*buf++, off);
+ else if (can_bank2)
+ cmos_write_bank2(*buf++, off);
+ else
+ break;
}
spin_unlock_irq(&rtc_lock);
@@ -539,7 +592,6 @@ static struct bin_attribute nvram = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.read = cmos_nvram_read,
@@ -631,8 +683,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
/* Heuristic to deduce NVRAM size ... do what the legacy NVRAM
* driver did, but don't reject unknown configs. Old hardware
- * won't address 128 bytes, and for now we ignore the way newer
- * chips can address 256 bytes (using two more i/o ports).
+ * won't address 128 bytes. Newer chips have multiple banks,
+ * though they may not be listed in one I/O resource.
*/
#if defined(CONFIG_ATARI)
address_space = 64;
@@ -642,6 +694,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
address_space = 128;
#endif
+ if (can_bank2 && ports->end > (ports->start + 1))
+ address_space = 256;
/* For ACPI systems extension info comes from the FADT. On others,
* board specific setup provides it as appropriate. Systems where
@@ -740,7 +794,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto cleanup2;
}
- pr_info("%s: alarms up to one %s%s%s\n",
+ pr_info("%s: alarms up to one %s%s, %zd bytes nvram, %s irqs\n",
cmos_rtc.rtc->dev.bus_id,
is_valid_irq(rtc_irq)
? (cmos_rtc.mon_alrm
@@ -749,6 +803,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
? "month" : "day"))
: "no",
cmos_rtc.century ? ", y3k" : "",
+ nvram.size,
is_hpet_enabled() ? ", hpet irqs" : "");
return 0;
diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c
index 0b17770b032..9a234a4ec06 100644
--- a/drivers/rtc/rtc-ds1216.c
+++ b/drivers/rtc/rtc-ds1216.c
@@ -86,19 +86,19 @@ static int ds1216_rtc_read_time(struct device *dev, struct rtc_time *tm)
ds1216_switch_ds_to_clock(priv->ioaddr);
ds1216_read(priv->ioaddr, (u8 *)&regs);
- tm->tm_sec = BCD2BIN(regs.sec);
- tm->tm_min = BCD2BIN(regs.min);
+ tm->tm_sec = bcd2bin(regs.sec);
+ tm->tm_min = bcd2bin(regs.min);
if (regs.hour & DS1216_HOUR_1224) {
/* AM/PM mode */
- tm->tm_hour = BCD2BIN(regs.hour & 0x1f);
+ tm->tm_hour = bcd2bin(regs.hour & 0x1f);
if (regs.hour & DS1216_HOUR_AMPM)
tm->tm_hour += 12;
} else
- tm->tm_hour = BCD2BIN(regs.hour & 0x3f);
+ tm->tm_hour = bcd2bin(regs.hour & 0x3f);
tm->tm_wday = (regs.wday & 7) - 1;
- tm->tm_mday = BCD2BIN(regs.mday & 0x3f);
- tm->tm_mon = BCD2BIN(regs.month & 0x1f);
- tm->tm_year = BCD2BIN(regs.year);
+ tm->tm_mday = bcd2bin(regs.mday & 0x3f);
+ tm->tm_mon = bcd2bin(regs.month & 0x1f);
+ tm->tm_year = bcd2bin(regs.year);
if (tm->tm_year < 70)
tm->tm_year += 100;
return 0;
@@ -114,19 +114,19 @@ static int ds1216_rtc_set_time(struct device *dev, struct rtc_time *tm)
ds1216_read(priv->ioaddr, (u8 *)&regs);
regs.tsec = 0; /* clear 0.1 and 0.01 seconds */
- regs.sec = BIN2BCD(tm->tm_sec);
- regs.min = BIN2BCD(tm->tm_min);
+ regs.sec = bin2bcd(tm->tm_sec);
+ regs.min = bin2bcd(tm->tm_min);
regs.hour &= DS1216_HOUR_1224;
if (regs.hour && tm->tm_hour > 12) {
regs.hour |= DS1216_HOUR_AMPM;
tm->tm_hour -= 12;
}
- regs.hour |= BIN2BCD(tm->tm_hour);
+ regs.hour |= bin2bcd(tm->tm_hour);
regs.wday &= ~7;
regs.wday |= tm->tm_wday;
- regs.mday = BIN2BCD(tm->tm_mday);
- regs.month = BIN2BCD(tm->tm_mon);
- regs.year = BIN2BCD(tm->tm_year % 100);
+ regs.mday = bin2bcd(tm->tm_mday);
+ regs.month = bin2bcd(tm->tm_mon);
+ regs.year = bin2bcd(tm->tm_year % 100);
ds1216_switch_ds_to_clock(priv->ioaddr);
ds1216_write(priv->ioaddr, (u8 *)&regs);
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index b9397818f73..18455662077 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -40,7 +40,7 @@
#define RTC_SCLK 0x0400
#ifdef CONFIG_SH_SECUREEDGE5410
-#include <asm/snapgear.h>
+#include <mach/snapgear.h>
#define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
#define get_dp() SECUREEDGE_READ_IOPORT()
#else
@@ -107,13 +107,13 @@ static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
spin_lock_irq(&rtc->lock);
- tm->tm_sec = BCD2BIN(ds1302_readbyte(RTC_ADDR_SEC));
- tm->tm_min = BCD2BIN(ds1302_readbyte(RTC_ADDR_MIN));
- tm->tm_hour = BCD2BIN(ds1302_readbyte(RTC_ADDR_HOUR));
- tm->tm_wday = BCD2BIN(ds1302_readbyte(RTC_ADDR_DAY));
- tm->tm_mday = BCD2BIN(ds1302_readbyte(RTC_ADDR_DATE));
- tm->tm_mon = BCD2BIN(ds1302_readbyte(RTC_ADDR_MON)) - 1;
- tm->tm_year = BCD2BIN(ds1302_readbyte(RTC_ADDR_YEAR));
+ tm->tm_sec = bcd2bin(ds1302_readbyte(RTC_ADDR_SEC));
+ tm->tm_min = bcd2bin(ds1302_readbyte(RTC_ADDR_MIN));
+ tm->tm_hour = bcd2bin(ds1302_readbyte(RTC_ADDR_HOUR));
+ tm->tm_wday = bcd2bin(ds1302_readbyte(RTC_ADDR_DAY));
+ tm->tm_mday = bcd2bin(ds1302_readbyte(RTC_ADDR_DATE));
+ tm->tm_mon = bcd2bin(ds1302_readbyte(RTC_ADDR_MON)) - 1;
+ tm->tm_year = bcd2bin(ds1302_readbyte(RTC_ADDR_YEAR));
if (tm->tm_year < 70)
tm->tm_year += 100;
@@ -141,13 +141,13 @@ static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* Stop RTC */
ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
- ds1302_writebyte(RTC_ADDR_SEC, BIN2BCD(tm->tm_sec));
- ds1302_writebyte(RTC_ADDR_MIN, BIN2BCD(tm->tm_min));
- ds1302_writebyte(RTC_ADDR_HOUR, BIN2BCD(tm->tm_hour));
- ds1302_writebyte(RTC_ADDR_DAY, BIN2BCD(tm->tm_wday));
- ds1302_writebyte(RTC_ADDR_DATE, BIN2BCD(tm->tm_mday));
- ds1302_writebyte(RTC_ADDR_MON, BIN2BCD(tm->tm_mon + 1));
- ds1302_writebyte(RTC_ADDR_YEAR, BIN2BCD(tm->tm_year % 100));
+ ds1302_writebyte(RTC_ADDR_SEC, bin2bcd(tm->tm_sec));
+ ds1302_writebyte(RTC_ADDR_MIN, bin2bcd(tm->tm_min));
+ ds1302_writebyte(RTC_ADDR_HOUR, bin2bcd(tm->tm_hour));
+ ds1302_writebyte(RTC_ADDR_DAY, bin2bcd(tm->tm_wday));
+ ds1302_writebyte(RTC_ADDR_DATE, bin2bcd(tm->tm_mday));
+ ds1302_writebyte(RTC_ADDR_MON, bin2bcd(tm->tm_mon + 1));
+ ds1302_writebyte(RTC_ADDR_YEAR, bin2bcd(tm->tm_year % 100));
/* Start RTC */
ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index b91d02a3ace..fc372df6534 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -114,10 +114,10 @@ static unsigned bcd2hour(u8 bcd)
hour = 12;
bcd &= ~DS1305_HR_PM;
}
- hour += BCD2BIN(bcd);
+ hour += bcd2bin(bcd);
return hour - 1;
}
- return BCD2BIN(bcd);
+ return bcd2bin(bcd);
}
static u8 hour2bcd(bool hr12, int hour)
@@ -125,11 +125,11 @@ static u8 hour2bcd(bool hr12, int hour)
if (hr12) {
hour++;
if (hour <= 12)
- return DS1305_HR_12 | BIN2BCD(hour);
+ return DS1305_HR_12 | bin2bcd(hour);
hour -= 12;
- return DS1305_HR_12 | DS1305_HR_PM | BIN2BCD(hour);
+ return DS1305_HR_12 | DS1305_HR_PM | bin2bcd(hour);
}
- return BIN2BCD(hour);
+ return bin2bcd(hour);
}
/*----------------------------------------------------------------------*/
@@ -206,13 +206,13 @@ static int ds1305_get_time(struct device *dev, struct rtc_time *time)
buf[4], buf[5], buf[6]);
/* Decode the registers */
- time->tm_sec = BCD2BIN(buf[DS1305_SEC]);
- time->tm_min = BCD2BIN(buf[DS1305_MIN]);
+ time->tm_sec = bcd2bin(buf[DS1305_SEC]);
+ time->tm_min = bcd2bin(buf[DS1305_MIN]);
time->tm_hour = bcd2hour(buf[DS1305_HOUR]);
time->tm_wday = buf[DS1305_WDAY] - 1;
- time->tm_mday = BCD2BIN(buf[DS1305_MDAY]);
- time->tm_mon = BCD2BIN(buf[DS1305_MON]) - 1;
- time->tm_year = BCD2BIN(buf[DS1305_YEAR]) + 100;
+ time->tm_mday = bcd2bin(buf[DS1305_MDAY]);
+ time->tm_mon = bcd2bin(buf[DS1305_MON]) - 1;
+ time->tm_year = bcd2bin(buf[DS1305_YEAR]) + 100;
dev_vdbg(dev, "%s secs=%d, mins=%d, "
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -239,13 +239,13 @@ static int ds1305_set_time(struct device *dev, struct rtc_time *time)
/* Write registers starting at the first time/date address. */
*bp++ = DS1305_WRITE | DS1305_SEC;
- *bp++ = BIN2BCD(time->tm_sec);
- *bp++ = BIN2BCD(time->tm_min);
+ *bp++ = bin2bcd(time->tm_sec);
+ *bp++ = bin2bcd(time->tm_min);
*bp++ = hour2bcd(ds1305->hr12, time->tm_hour);
*bp++ = (time->tm_wday < 7) ? (time->tm_wday + 1) : 1;
- *bp++ = BIN2BCD(time->tm_mday);
- *bp++ = BIN2BCD(time->tm_mon + 1);
- *bp++ = BIN2BCD(time->tm_year - 100);
+ *bp++ = bin2bcd(time->tm_mday);
+ *bp++ = bin2bcd(time->tm_mon + 1);
+ *bp++ = bin2bcd(time->tm_year - 100);
dev_dbg(dev, "%s: %02x %02x %02x, %02x %02x %02x %02x\n",
"write", buf[1], buf[2], buf[3],
@@ -329,8 +329,8 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
* fill in the rest ... and also handle rollover to tomorrow when
* that's needed.
*/
- alm->time.tm_sec = BCD2BIN(buf[DS1305_SEC]);
- alm->time.tm_min = BCD2BIN(buf[DS1305_MIN]);
+ alm->time.tm_sec = bcd2bin(buf[DS1305_SEC]);
+ alm->time.tm_min = bcd2bin(buf[DS1305_MIN]);
alm->time.tm_hour = bcd2hour(buf[DS1305_HOUR]);
alm->time.tm_mday = -1;
alm->time.tm_mon = -1;
@@ -387,8 +387,8 @@ static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
/* write alarm */
buf[0] = DS1305_WRITE | DS1305_ALM0(DS1305_SEC);
- buf[1 + DS1305_SEC] = BIN2BCD(alm->time.tm_sec);
- buf[1 + DS1305_MIN] = BIN2BCD(alm->time.tm_min);
+ buf[1 + DS1305_SEC] = bin2bcd(alm->time.tm_sec);
+ buf[1 + DS1305_MIN] = bin2bcd(alm->time.tm_min);
buf[1 + DS1305_HOUR] = hour2bcd(ds1305->hr12, alm->time.tm_hour);
buf[1 + DS1305_WDAY] = DS1305_ALM_DISABLE;
@@ -606,7 +606,6 @@ ds1305_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
static struct bin_attribute nvram = {
.attr.name = "nvram",
.attr.mode = S_IRUGO | S_IWUSR,
- .attr.owner = THIS_MODULE,
.read = ds1305_nvram_read,
.write = ds1305_nvram_write,
.size = DS1305_NVRAM_LEN,
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 4fcf0734a6e..162330b9d1d 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -222,17 +222,17 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
ds1307->regs[4], ds1307->regs[5],
ds1307->regs[6]);
- t->tm_sec = BCD2BIN(ds1307->regs[DS1307_REG_SECS] & 0x7f);
- t->tm_min = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+ t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f);
+ t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
tmp = ds1307->regs[DS1307_REG_HOUR] & 0x3f;
- t->tm_hour = BCD2BIN(tmp);
- t->tm_wday = BCD2BIN(ds1307->regs[DS1307_REG_WDAY] & 0x07) - 1;
- t->tm_mday = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+ t->tm_hour = bcd2bin(tmp);
+ t->tm_wday = bcd2bin(ds1307->regs[DS1307_REG_WDAY] & 0x07) - 1;
+ t->tm_mday = bcd2bin(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
tmp = ds1307->regs[DS1307_REG_MONTH] & 0x1f;
- t->tm_mon = BCD2BIN(tmp) - 1;
+ t->tm_mon = bcd2bin(tmp) - 1;
/* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */
- t->tm_year = BCD2BIN(ds1307->regs[DS1307_REG_YEAR]) + 100;
+ t->tm_year = bcd2bin(ds1307->regs[DS1307_REG_YEAR]) + 100;
dev_dbg(dev, "%s secs=%d, mins=%d, "
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -258,16 +258,16 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
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);
- buf[DS1307_REG_WDAY] = BIN2BCD(t->tm_wday + 1);
- buf[DS1307_REG_MDAY] = BIN2BCD(t->tm_mday);
- buf[DS1307_REG_MONTH] = BIN2BCD(t->tm_mon + 1);
+ buf[DS1307_REG_SECS] = bin2bcd(t->tm_sec);
+ buf[DS1307_REG_MIN] = bin2bcd(t->tm_min);
+ buf[DS1307_REG_HOUR] = bin2bcd(t->tm_hour);
+ buf[DS1307_REG_WDAY] = bin2bcd(t->tm_wday + 1);
+ buf[DS1307_REG_MDAY] = bin2bcd(t->tm_mday);
+ buf[DS1307_REG_MONTH] = bin2bcd(t->tm_mon + 1);
/* assume 20YY not 19YY */
tmp = t->tm_year - 100;
- buf[DS1307_REG_YEAR] = BIN2BCD(tmp);
+ buf[DS1307_REG_YEAR] = bin2bcd(tmp);
switch (ds1307->type) {
case ds_1337:
@@ -551,7 +551,6 @@ static struct bin_attribute nvram = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.read = ds1307_nvram_read,
@@ -709,18 +708,18 @@ read_rtc:
}
tmp = ds1307->regs[DS1307_REG_SECS];
- tmp = BCD2BIN(tmp & 0x7f);
+ tmp = bcd2bin(tmp & 0x7f);
if (tmp > 60)
goto exit_bad;
- tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+ tmp = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
if (tmp > 60)
goto exit_bad;
- tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+ tmp = bcd2bin(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
if (tmp == 0 || tmp > 31)
goto exit_bad;
- tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f);
+ tmp = bcd2bin(ds1307->regs[DS1307_REG_MONTH] & 0x1f);
if (tmp == 0 || tmp > 12)
goto exit_bad;
@@ -739,14 +738,14 @@ read_rtc:
/* Be sure we're in 24 hour mode. Multi-master systems
* take note...
*/
- tmp = BCD2BIN(tmp & 0x1f);
+ tmp = bcd2bin(tmp & 0x1f);
if (tmp == 12)
tmp = 0;
if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
tmp += 12;
i2c_smbus_write_byte_data(client,
DS1307_REG_HOUR,
- BIN2BCD(tmp));
+ bin2bcd(tmp));
}
ds1307->rtc = rtc_device_register(client->name, &client->dev,
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 86981d34fbb..25caada7839 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -153,8 +153,8 @@ ds1511_wdog_set(unsigned long deciseconds)
/*
* set the wdog values in the wdog registers
*/
- rtc_write(BIN2BCD(deciseconds % 100), DS1511_WD_MSEC);
- rtc_write(BIN2BCD(deciseconds / 100), DS1511_WD_SEC);
+ rtc_write(bin2bcd(deciseconds % 100), DS1511_WD_MSEC);
+ rtc_write(bin2bcd(deciseconds / 100), DS1511_WD_SEC);
/*
* set wdog enable and wdog 'steering' bit to issue a reset
*/
@@ -220,13 +220,13 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
/*
* each register is a different number of valid bits
*/
- sec = BIN2BCD(sec) & 0x7f;
- min = BIN2BCD(min) & 0x7f;
- hrs = BIN2BCD(hrs) & 0x3f;
- day = BIN2BCD(day) & 0x3f;
- mon = BIN2BCD(mon) & 0x1f;
- yrs = BIN2BCD(yrs) & 0xff;
- cen = BIN2BCD(cen) & 0xff;
+ sec = bin2bcd(sec) & 0x7f;
+ min = bin2bcd(min) & 0x7f;
+ hrs = bin2bcd(hrs) & 0x3f;
+ day = bin2bcd(day) & 0x3f;
+ mon = bin2bcd(mon) & 0x1f;
+ yrs = bin2bcd(yrs) & 0xff;
+ cen = bin2bcd(cen) & 0xff;
spin_lock_irqsave(&ds1511_lock, flags);
rtc_disable_update();
@@ -264,14 +264,14 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
rtc_enable_update();
spin_unlock_irqrestore(&ds1511_lock, flags);
- rtc_tm->tm_sec = BCD2BIN(rtc_tm->tm_sec);
- rtc_tm->tm_min = BCD2BIN(rtc_tm->tm_min);
- rtc_tm->tm_hour = BCD2BIN(rtc_tm->tm_hour);
- rtc_tm->tm_mday = BCD2BIN(rtc_tm->tm_mday);
- rtc_tm->tm_wday = BCD2BIN(rtc_tm->tm_wday);
- rtc_tm->tm_mon = BCD2BIN(rtc_tm->tm_mon);
- rtc_tm->tm_year = BCD2BIN(rtc_tm->tm_year);
- century = BCD2BIN(century) * 100;
+ rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
+ rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
+ rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
+ rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
+ rtc_tm->tm_wday = bcd2bin(rtc_tm->tm_wday);
+ rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
+ rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
+ century = bcd2bin(century) * 100;
/*
* Account for differences between how the RTC uses the values
@@ -304,16 +304,16 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_mday) & 0x3f,
+ 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f,
RTC_ALARM_DATE);
rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_hour) & 0x3f,
+ 0x80 : bin2bcd(pdata->alrm_hour) & 0x3f,
RTC_ALARM_HOUR);
rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_min) & 0x7f,
+ 0x80 : bin2bcd(pdata->alrm_min) & 0x7f,
RTC_ALARM_MIN);
rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_sec) & 0x7f,
+ 0x80 : bin2bcd(pdata->alrm_sec) & 0x7f,
RTC_ALARM_SEC);
rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
rtc_read(RTC_CMD1); /* clear interrupts */
@@ -481,7 +481,6 @@ static struct bin_attribute ds1511_nvram_attr = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUGO,
- .owner = THIS_MODULE,
},
.size = DS1511_RAM_MAX,
.read = ds1511_nvram_read,
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 4ef59285b48..b9475cd2021 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -78,17 +78,17 @@ static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm)
void __iomem *ioaddr = pdata->ioaddr;
u8 century;
- century = BIN2BCD((tm->tm_year + 1900) / 100);
+ century = bin2bcd((tm->tm_year + 1900) / 100);
writeb(RTC_WRITE, pdata->ioaddr + RTC_CONTROL);
- writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
- writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
- writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
- writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
- writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
- writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
- writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+ writeb(bin2bcd(tm->tm_year % 100), ioaddr + RTC_YEAR);
+ writeb(bin2bcd(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+ writeb(bin2bcd(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+ writeb(bin2bcd(tm->tm_mday), ioaddr + RTC_DATE);
+ writeb(bin2bcd(tm->tm_hour), ioaddr + RTC_HOURS);
+ writeb(bin2bcd(tm->tm_min), ioaddr + RTC_MINUTES);
+ writeb(bin2bcd(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
/* RTC_CENTURY and RTC_CONTROL share same register */
writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
@@ -118,14 +118,14 @@ static int ds1553_rtc_read_time(struct device *dev, struct rtc_time *tm)
year = readb(ioaddr + RTC_YEAR);
century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
writeb(0, ioaddr + RTC_CONTROL);
- tm->tm_sec = BCD2BIN(second);
- tm->tm_min = BCD2BIN(minute);
- tm->tm_hour = BCD2BIN(hour);
- tm->tm_mday = BCD2BIN(day);
- tm->tm_wday = BCD2BIN(week);
- tm->tm_mon = BCD2BIN(month) - 1;
+ tm->tm_sec = bcd2bin(second);
+ tm->tm_min = bcd2bin(minute);
+ tm->tm_hour = bcd2bin(hour);
+ tm->tm_mday = bcd2bin(day);
+ tm->tm_wday = bcd2bin(week);
+ tm->tm_mon = bcd2bin(month) - 1;
/* year is 1900 + tm->tm_year */
- tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+ tm->tm_year = bcd2bin(year) + bcd2bin(century) * 100 - 1900;
if (rtc_valid_tm(tm) < 0) {
dev_err(dev, "retrieved date/time is not valid.\n");
@@ -141,16 +141,16 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)
spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_mday),
+ 0x80 : bin2bcd(pdata->alrm_mday),
ioaddr + RTC_DATE_ALARM);
writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_hour),
+ 0x80 : bin2bcd(pdata->alrm_hour),
ioaddr + RTC_HOURS_ALARM);
writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_min),
+ 0x80 : bin2bcd(pdata->alrm_min),
ioaddr + RTC_MINUTES_ALARM);
writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_sec),
+ 0x80 : bin2bcd(pdata->alrm_sec),
ioaddr + RTC_SECONDS_ALARM);
writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS);
readb(ioaddr + RTC_FLAGS); /* clear interrupts */
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 24d35ede2db..8bc8501bffc 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -66,17 +66,17 @@ static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm)
void __iomem *ioaddr = pdata->ioaddr_rtc;
u8 century;
- century = BIN2BCD((tm->tm_year + 1900) / 100);
+ century = bin2bcd((tm->tm_year + 1900) / 100);
writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
- writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
- writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
- writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
- writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
- writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
- writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
- writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+ writeb(bin2bcd(tm->tm_year % 100), ioaddr + RTC_YEAR);
+ writeb(bin2bcd(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+ writeb(bin2bcd(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+ writeb(bin2bcd(tm->tm_mday), ioaddr + RTC_DATE);
+ writeb(bin2bcd(tm->tm_hour), ioaddr + RTC_HOURS);
+ writeb(bin2bcd(tm->tm_min), ioaddr + RTC_MINUTES);
+ writeb(bin2bcd(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
/* RTC_CENTURY and RTC_CONTROL share same register */
writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
@@ -106,14 +106,14 @@ static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm)
year = readb(ioaddr + RTC_YEAR);
century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
writeb(0, ioaddr + RTC_CONTROL);
- tm->tm_sec = BCD2BIN(second);
- tm->tm_min = BCD2BIN(minute);
- tm->tm_hour = BCD2BIN(hour);
- tm->tm_mday = BCD2BIN(day);
- tm->tm_wday = BCD2BIN(week);
- tm->tm_mon = BCD2BIN(month) - 1;
+ tm->tm_sec = bcd2bin(second);
+ tm->tm_min = bcd2bin(minute);
+ tm->tm_hour = bcd2bin(hour);
+ tm->tm_mday = bcd2bin(day);
+ tm->tm_wday = bcd2bin(week);
+ tm->tm_mon = bcd2bin(month) - 1;
/* year is 1900 + tm->tm_year */
- tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+ tm->tm_year = bcd2bin(year) + bcd2bin(century) * 100 - 1900;
if (rtc_valid_tm(tm) < 0) {
dev_err(dev, "retrieved date/time is not valid.\n");
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index abfdfcbaa05..3a7be11cc6b 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -131,17 +131,17 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
fm3130->regs[0xc], fm3130->regs[0xd],
fm3130->regs[0xe]);
- t->tm_sec = BCD2BIN(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
- t->tm_min = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
+ t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
+ t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
tmp = fm3130->regs[FM3130_RTC_HOURS] & 0x3f;
- t->tm_hour = BCD2BIN(tmp);
- t->tm_wday = BCD2BIN(fm3130->regs[FM3130_RTC_DAY] & 0x07) - 1;
- t->tm_mday = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
+ t->tm_hour = bcd2bin(tmp);
+ t->tm_wday = bcd2bin(fm3130->regs[FM3130_RTC_DAY] & 0x07) - 1;
+ t->tm_mday = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
tmp = fm3130->regs[FM3130_RTC_MONTHS] & 0x1f;
- t->tm_mon = BCD2BIN(tmp) - 1;
+ t->tm_mon = bcd2bin(tmp) - 1;
/* assume 20YY not 19YY, and ignore CF bit */
- t->tm_year = BCD2BIN(fm3130->regs[FM3130_RTC_YEARS]) + 100;
+ t->tm_year = bcd2bin(fm3130->regs[FM3130_RTC_YEARS]) + 100;
dev_dbg(dev, "%s secs=%d, mins=%d, "
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -167,16 +167,16 @@ static int fm3130_set_time(struct device *dev, struct rtc_time *t)
t->tm_mon, t->tm_year, t->tm_wday);
/* first register addr */
- buf[FM3130_RTC_SECONDS] = BIN2BCD(t->tm_sec);
- buf[FM3130_RTC_MINUTES] = BIN2BCD(t->tm_min);
- buf[FM3130_RTC_HOURS] = BIN2BCD(t->tm_hour);
- buf[FM3130_RTC_DAY] = BIN2BCD(t->tm_wday + 1);
- buf[FM3130_RTC_DATE] = BIN2BCD(t->tm_mday);
- buf[FM3130_RTC_MONTHS] = BIN2BCD(t->tm_mon + 1);
+ buf[FM3130_RTC_SECONDS] = bin2bcd(t->tm_sec);
+ buf[FM3130_RTC_MINUTES] = bin2bcd(t->tm_min);
+ buf[FM3130_RTC_HOURS] = bin2bcd(t->tm_hour);
+ buf[FM3130_RTC_DAY] = bin2bcd(t->tm_wday + 1);
+ buf[FM3130_RTC_DATE] = bin2bcd(t->tm_mday);
+ buf[FM3130_RTC_MONTHS] = bin2bcd(t->tm_mon + 1);
/* assume 20YY not 19YY */
tmp = t->tm_year - 100;
- buf[FM3130_RTC_YEARS] = BIN2BCD(tmp);
+ buf[FM3130_RTC_YEARS] = bin2bcd(tmp);
dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x"
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
@@ -222,11 +222,11 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
fm3130->regs[FM3130_ALARM_MONTHS]);
- tm->tm_sec = BCD2BIN(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F);
- tm->tm_min = BCD2BIN(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F);
- tm->tm_hour = BCD2BIN(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F);
- tm->tm_mday = BCD2BIN(fm3130->regs[FM3130_ALARM_DATE] & 0x3F);
- tm->tm_mon = BCD2BIN(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F);
+ tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F);
+ tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F);
+ tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F);
+ tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F);
+ tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F);
if (tm->tm_mon > 0)
tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
dev_dbg(dev, "%s secs=%d, mins=%d, "
@@ -252,23 +252,23 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (tm->tm_sec != -1)
fm3130->regs[FM3130_ALARM_SECONDS] =
- BIN2BCD(tm->tm_sec) | 0x80;
+ bin2bcd(tm->tm_sec) | 0x80;
if (tm->tm_min != -1)
fm3130->regs[FM3130_ALARM_MINUTES] =
- BIN2BCD(tm->tm_min) | 0x80;
+ bin2bcd(tm->tm_min) | 0x80;
if (tm->tm_hour != -1)
fm3130->regs[FM3130_ALARM_HOURS] =
- BIN2BCD(tm->tm_hour) | 0x80;
+ bin2bcd(tm->tm_hour) | 0x80;
if (tm->tm_mday != -1)
fm3130->regs[FM3130_ALARM_DATE] =
- BIN2BCD(tm->tm_mday) | 0x80;
+ bin2bcd(tm->tm_mday) | 0x80;
if (tm->tm_mon != -1)
fm3130->regs[FM3130_ALARM_MONTHS] =
- BIN2BCD(tm->tm_mon + 1) | 0x80;
+ bin2bcd(tm->tm_mon + 1) | 0x80;
dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n",
fm3130->regs[FM3130_ALARM_SECONDS],
@@ -414,18 +414,18 @@ static int __devinit fm3130_probe(struct i2c_client *client,
/* TODO */
/* TODO need to sanity check alarm */
tmp = fm3130->regs[FM3130_RTC_SECONDS];
- tmp = BCD2BIN(tmp & 0x7f);
+ tmp = bcd2bin(tmp & 0x7f);
if (tmp > 60)
goto exit_bad;
- tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
+ tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
if (tmp > 60)
goto exit_bad;
- tmp = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
+ tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
if (tmp == 0 || tmp > 31)
goto exit_bad;
- tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
+ tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
if (tmp == 0 || tmp > 12)
goto exit_bad;
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index a81adab6e51..2cd77ab8fc6 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -259,26 +259,26 @@ isl1208_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
return sr;
}
- tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]);
- tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]);
+ tm->tm_sec = bcd2bin(regs[ISL1208_REG_SC]);
+ tm->tm_min = bcd2bin(regs[ISL1208_REG_MN]);
/* HR field has a more complex interpretation */
{
const u8 _hr = regs[ISL1208_REG_HR];
if (_hr & ISL1208_REG_HR_MIL) /* 24h format */
- tm->tm_hour = BCD2BIN(_hr & 0x3f);
+ tm->tm_hour = bcd2bin(_hr & 0x3f);
else {
/* 12h format */
- tm->tm_hour = BCD2BIN(_hr & 0x1f);
+ tm->tm_hour = bcd2bin(_hr & 0x1f);
if (_hr & ISL1208_REG_HR_PM) /* PM flag set */
tm->tm_hour += 12;
}
}
- tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]);
- tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */
- tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100;
- tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]);
+ tm->tm_mday = bcd2bin(regs[ISL1208_REG_DT]);
+ tm->tm_mon = bcd2bin(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */
+ tm->tm_year = bcd2bin(regs[ISL1208_REG_YR]) + 100;
+ tm->tm_wday = bcd2bin(regs[ISL1208_REG_DW]);
return 0;
}
@@ -305,13 +305,13 @@ isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
}
/* MSB of each alarm register is an enable bit */
- tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA - ISL1208_REG_SCA] & 0x7f);
- tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA - ISL1208_REG_SCA] & 0x7f);
- tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA - ISL1208_REG_SCA] & 0x3f);
- tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA - ISL1208_REG_SCA] & 0x3f);
+ tm->tm_sec = bcd2bin(regs[ISL1208_REG_SCA - ISL1208_REG_SCA] & 0x7f);
+ tm->tm_min = bcd2bin(regs[ISL1208_REG_MNA - ISL1208_REG_SCA] & 0x7f);
+ tm->tm_hour = bcd2bin(regs[ISL1208_REG_HRA - ISL1208_REG_SCA] & 0x3f);
+ tm->tm_mday = bcd2bin(regs[ISL1208_REG_DTA - ISL1208_REG_SCA] & 0x3f);
tm->tm_mon =
- BCD2BIN(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1;
- tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03);
+ bcd2bin(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1;
+ tm->tm_wday = bcd2bin(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03);
return 0;
}
@@ -328,15 +328,15 @@ isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
int sr;
u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
- regs[ISL1208_REG_SC] = BIN2BCD(tm->tm_sec);
- regs[ISL1208_REG_MN] = BIN2BCD(tm->tm_min);
- regs[ISL1208_REG_HR] = BIN2BCD(tm->tm_hour) | ISL1208_REG_HR_MIL;
+ regs[ISL1208_REG_SC] = bin2bcd(tm->tm_sec);
+ regs[ISL1208_REG_MN] = bin2bcd(tm->tm_min);
+ regs[ISL1208_REG_HR] = bin2bcd(tm->tm_hour) | ISL1208_REG_HR_MIL;
- regs[ISL1208_REG_DT] = BIN2BCD(tm->tm_mday);
- regs[ISL1208_REG_MO] = BIN2BCD(tm->tm_mon + 1);
- regs[ISL1208_REG_YR] = BIN2BCD(tm->tm_year - 100);
+ regs[ISL1208_REG_DT] = bin2bcd(tm->tm_mday);
+ regs[ISL1208_REG_MO] = bin2bcd(tm->tm_mon + 1);
+ regs[ISL1208_REG_YR] = bin2bcd(tm->tm_year - 100);
- regs[ISL1208_REG_DW] = BIN2BCD(tm->tm_wday & 7);
+ regs[ISL1208_REG_DW] = bin2bcd(tm->tm_wday & 7);
sr = isl1208_i2c_get_sr(client);
if (sr < 0) {
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 470fb2d2954..893f7dece23 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -110,15 +110,15 @@ static int m41t80_get_datetime(struct i2c_client *client,
return -EIO;
}
- tm->tm_sec = BCD2BIN(buf[M41T80_REG_SEC] & 0x7f);
- tm->tm_min = BCD2BIN(buf[M41T80_REG_MIN] & 0x7f);
- tm->tm_hour = BCD2BIN(buf[M41T80_REG_HOUR] & 0x3f);
- tm->tm_mday = BCD2BIN(buf[M41T80_REG_DAY] & 0x3f);
+ tm->tm_sec = bcd2bin(buf[M41T80_REG_SEC] & 0x7f);
+ tm->tm_min = bcd2bin(buf[M41T80_REG_MIN] & 0x7f);
+ tm->tm_hour = bcd2bin(buf[M41T80_REG_HOUR] & 0x3f);
+ tm->tm_mday = bcd2bin(buf[M41T80_REG_DAY] & 0x3f);
tm->tm_wday = buf[M41T80_REG_WDAY] & 0x07;
- tm->tm_mon = BCD2BIN(buf[M41T80_REG_MON] & 0x1f) - 1;
+ tm->tm_mon = bcd2bin(buf[M41T80_REG_MON] & 0x1f) - 1;
/* assume 20YY not 19YY, and ignore the Century Bit */
- tm->tm_year = BCD2BIN(buf[M41T80_REG_YEAR]) + 100;
+ tm->tm_year = bcd2bin(buf[M41T80_REG_YEAR]) + 100;
return 0;
}
@@ -161,19 +161,19 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
/* Merge time-data and register flags into buf[0..7] */
buf[M41T80_REG_SSEC] = 0;
buf[M41T80_REG_SEC] =
- BIN2BCD(tm->tm_sec) | (buf[M41T80_REG_SEC] & ~0x7f);
+ bin2bcd(tm->tm_sec) | (buf[M41T80_REG_SEC] & ~0x7f);
buf[M41T80_REG_MIN] =
- BIN2BCD(tm->tm_min) | (buf[M41T80_REG_MIN] & ~0x7f);
+ bin2bcd(tm->tm_min) | (buf[M41T80_REG_MIN] & ~0x7f);
buf[M41T80_REG_HOUR] =
- BIN2BCD(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f) ;
+ bin2bcd(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f) ;
buf[M41T80_REG_WDAY] =
(tm->tm_wday & 0x07) | (buf[M41T80_REG_WDAY] & ~0x07);
buf[M41T80_REG_DAY] =
- BIN2BCD(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f);
+ bin2bcd(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f);
buf[M41T80_REG_MON] =
- BIN2BCD(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f);
+ bin2bcd(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f);
/* assume 20YY not 19YY */
- buf[M41T80_REG_YEAR] = BIN2BCD(tm->tm_year % 100);
+ buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year % 100);
if (i2c_transfer(client->adapter, msgs, 1) != 1) {
dev_err(&client->dev, "write error\n");
@@ -288,15 +288,15 @@ static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
wbuf[0] = M41T80_REG_ALARM_MON; /* offset into rtc's regs */
reg[M41T80_REG_ALARM_SEC] |= t->time.tm_sec >= 0 ?
- BIN2BCD(t->time.tm_sec) : 0x80;
+ bin2bcd(t->time.tm_sec) : 0x80;
reg[M41T80_REG_ALARM_MIN] |= t->time.tm_min >= 0 ?
- BIN2BCD(t->time.tm_min) : 0x80;
+ bin2bcd(t->time.tm_min) : 0x80;
reg[M41T80_REG_ALARM_HOUR] |= t->time.tm_hour >= 0 ?
- BIN2BCD(t->time.tm_hour) : 0x80;
+ bin2bcd(t->time.tm_hour) : 0x80;
reg[M41T80_REG_ALARM_DAY] |= t->time.tm_mday >= 0 ?
- BIN2BCD(t->time.tm_mday) : 0x80;
+ bin2bcd(t->time.tm_mday) : 0x80;
if (t->time.tm_mon >= 0)
- reg[M41T80_REG_ALARM_MON] |= BIN2BCD(t->time.tm_mon + 1);
+ reg[M41T80_REG_ALARM_MON] |= bin2bcd(t->time.tm_mon + 1);
else
reg[M41T80_REG_ALARM_DAY] |= 0x40;
@@ -347,15 +347,15 @@ static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
t->time.tm_mday = -1;
t->time.tm_mon = -1;
if (!(reg[M41T80_REG_ALARM_SEC] & 0x80))
- t->time.tm_sec = BCD2BIN(reg[M41T80_REG_ALARM_SEC] & 0x7f);
+ t->time.tm_sec = bcd2bin(reg[M41T80_REG_ALARM_SEC] & 0x7f);
if (!(reg[M41T80_REG_ALARM_MIN] & 0x80))
- t->time.tm_min = BCD2BIN(reg[M41T80_REG_ALARM_MIN] & 0x7f);
+ t->time.tm_min = bcd2bin(reg[M41T80_REG_ALARM_MIN] & 0x7f);
if (!(reg[M41T80_REG_ALARM_HOUR] & 0x80))
- t->time.tm_hour = BCD2BIN(reg[M41T80_REG_ALARM_HOUR] & 0x3f);
+ t->time.tm_hour = bcd2bin(reg[M41T80_REG_ALARM_HOUR] & 0x3f);
if (!(reg[M41T80_REG_ALARM_DAY] & 0x80))
- t->time.tm_mday = BCD2BIN(reg[M41T80_REG_ALARM_DAY] & 0x3f);
+ t->time.tm_mday = bcd2bin(reg[M41T80_REG_ALARM_DAY] & 0x3f);
if (!(reg[M41T80_REG_ALARM_DAY] & 0x40))
- t->time.tm_mon = BCD2BIN(reg[M41T80_REG_ALARM_MON] & 0x1f) - 1;
+ t->time.tm_mon = bcd2bin(reg[M41T80_REG_ALARM_MON] & 0x1f) - 1;
t->time.tm_year = -1;
t->time.tm_wday = -1;
t->time.tm_yday = -1;
diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c
index 9b19499c829..c3a18c58daf 100644
--- a/drivers/rtc/rtc-m41t94.c
+++ b/drivers/rtc/rtc-m41t94.c
@@ -41,17 +41,17 @@ static int m41t94_set_time(struct device *dev, struct rtc_time *tm)
tm->tm_mon, tm->tm_year, tm->tm_wday);
buf[0] = 0x80 | M41T94_REG_SECONDS; /* write time + date */
- buf[M41T94_REG_SECONDS] = BIN2BCD(tm->tm_sec);
- buf[M41T94_REG_MINUTES] = BIN2BCD(tm->tm_min);
- buf[M41T94_REG_HOURS] = BIN2BCD(tm->tm_hour);
- buf[M41T94_REG_WDAY] = BIN2BCD(tm->tm_wday + 1);
- buf[M41T94_REG_DAY] = BIN2BCD(tm->tm_mday);
- buf[M41T94_REG_MONTH] = BIN2BCD(tm->tm_mon + 1);
+ buf[M41T94_REG_SECONDS] = bin2bcd(tm->tm_sec);
+ buf[M41T94_REG_MINUTES] = bin2bcd(tm->tm_min);
+ buf[M41T94_REG_HOURS] = bin2bcd(tm->tm_hour);
+ buf[M41T94_REG_WDAY] = bin2bcd(tm->tm_wday + 1);
+ buf[M41T94_REG_DAY] = bin2bcd(tm->tm_mday);
+ buf[M41T94_REG_MONTH] = bin2bcd(tm->tm_mon + 1);
buf[M41T94_REG_HOURS] |= M41T94_BIT_CEB;
if (tm->tm_year >= 100)
buf[M41T94_REG_HOURS] |= M41T94_BIT_CB;
- buf[M41T94_REG_YEAR] = BIN2BCD(tm->tm_year % 100);
+ buf[M41T94_REG_YEAR] = bin2bcd(tm->tm_year % 100);
return spi_write(spi, buf, 8);
}
@@ -82,14 +82,14 @@ static int m41t94_read_time(struct device *dev, struct rtc_time *tm)
spi_write(spi, buf, 2);
}
- tm->tm_sec = BCD2BIN(spi_w8r8(spi, M41T94_REG_SECONDS));
- tm->tm_min = BCD2BIN(spi_w8r8(spi, M41T94_REG_MINUTES));
+ tm->tm_sec = bcd2bin(spi_w8r8(spi, M41T94_REG_SECONDS));
+ tm->tm_min = bcd2bin(spi_w8r8(spi, M41T94_REG_MINUTES));
hour = spi_w8r8(spi, M41T94_REG_HOURS);
- tm->tm_hour = BCD2BIN(hour & 0x3f);
- tm->tm_wday = BCD2BIN(spi_w8r8(spi, M41T94_REG_WDAY)) - 1;
- tm->tm_mday = BCD2BIN(spi_w8r8(spi, M41T94_REG_DAY));
- tm->tm_mon = BCD2BIN(spi_w8r8(spi, M41T94_REG_MONTH)) - 1;
- tm->tm_year = BCD2BIN(spi_w8r8(spi, M41T94_REG_YEAR));
+ tm->tm_hour = bcd2bin(hour & 0x3f);
+ tm->tm_wday = bcd2bin(spi_w8r8(spi, M41T94_REG_WDAY)) - 1;
+ tm->tm_mday = bcd2bin(spi_w8r8(spi, M41T94_REG_DAY));
+ tm->tm_mon = bcd2bin(spi_w8r8(spi, M41T94_REG_MONTH)) - 1;
+ tm->tm_year = bcd2bin(spi_w8r8(spi, M41T94_REG_YEAR));
if ((hour & M41T94_BIT_CB) || !(hour & M41T94_BIT_CEB))
tm->tm_year += 100;
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index ce4eff6a8d5..04b63dab693 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -76,10 +76,10 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
/* Issue the READ command */
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
- tm->tm_year = BCD2BIN(M48T59_READ(M48T59_YEAR));
+ tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR));
/* tm_mon is 0-11 */
- tm->tm_mon = BCD2BIN(M48T59_READ(M48T59_MONTH)) - 1;
- tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_MDAY));
+ tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
+ tm->tm_mday = bcd2bin(M48T59_READ(M48T59_MDAY));
val = M48T59_READ(M48T59_WDAY);
if ((pdata->type == M48T59RTC_TYPE_M48T59) &&
@@ -88,10 +88,10 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_year += 100; /* one century */
}
- tm->tm_wday = BCD2BIN(val & 0x07);
- tm->tm_hour = BCD2BIN(M48T59_READ(M48T59_HOUR) & 0x3F);
- tm->tm_min = BCD2BIN(M48T59_READ(M48T59_MIN) & 0x7F);
- tm->tm_sec = BCD2BIN(M48T59_READ(M48T59_SEC) & 0x7F);
+ tm->tm_wday = bcd2bin(val & 0x07);
+ tm->tm_hour = bcd2bin(M48T59_READ(M48T59_HOUR) & 0x3F);
+ tm->tm_min = bcd2bin(M48T59_READ(M48T59_MIN) & 0x7F);
+ tm->tm_sec = bcd2bin(M48T59_READ(M48T59_SEC) & 0x7F);
/* Clear the READ bit */
M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL);
@@ -119,17 +119,17 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* Issue the WRITE command */
M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL);
- M48T59_WRITE((BIN2BCD(tm->tm_sec) & 0x7F), M48T59_SEC);
- M48T59_WRITE((BIN2BCD(tm->tm_min) & 0x7F), M48T59_MIN);
- M48T59_WRITE((BIN2BCD(tm->tm_hour) & 0x3F), M48T59_HOUR);
- M48T59_WRITE((BIN2BCD(tm->tm_mday) & 0x3F), M48T59_MDAY);
+ M48T59_WRITE((bin2bcd(tm->tm_sec) & 0x7F), M48T59_SEC);
+ M48T59_WRITE((bin2bcd(tm->tm_min) & 0x7F), M48T59_MIN);
+ M48T59_WRITE((bin2bcd(tm->tm_hour) & 0x3F), M48T59_HOUR);
+ M48T59_WRITE((bin2bcd(tm->tm_mday) & 0x3F), M48T59_MDAY);
/* tm_mon is 0-11 */
- M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
- M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR);
+ M48T59_WRITE((bin2bcd(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
+ M48T59_WRITE(bin2bcd(tm->tm_year % 100), M48T59_YEAR);
if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100))
val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
- val |= (BIN2BCD(tm->tm_wday) & 0x07);
+ val |= (bin2bcd(tm->tm_wday) & 0x07);
M48T59_WRITE(val, M48T59_WDAY);
/* Clear the WRITE bit */
@@ -158,18 +158,18 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
/* Issue the READ command */
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
- tm->tm_year = BCD2BIN(M48T59_READ(M48T59_YEAR));
+ tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR));
/* tm_mon is 0-11 */
- tm->tm_mon = BCD2BIN(M48T59_READ(M48T59_MONTH)) - 1;
+ tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
val = M48T59_READ(M48T59_WDAY);
if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB))
tm->tm_year += 100; /* one century */
- tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_ALARM_DATE));
- tm->tm_hour = BCD2BIN(M48T59_READ(M48T59_ALARM_HOUR));
- tm->tm_min = BCD2BIN(M48T59_READ(M48T59_ALARM_MIN));
- tm->tm_sec = BCD2BIN(M48T59_READ(M48T59_ALARM_SEC));
+ tm->tm_mday = bcd2bin(M48T59_READ(M48T59_ALARM_DATE));
+ tm->tm_hour = bcd2bin(M48T59_READ(M48T59_ALARM_HOUR));
+ tm->tm_min = bcd2bin(M48T59_READ(M48T59_ALARM_MIN));
+ tm->tm_sec = bcd2bin(M48T59_READ(M48T59_ALARM_SEC));
/* Clear the READ bit */
M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL);
@@ -201,18 +201,18 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
* 0xff means "always match"
*/
mday = tm->tm_mday;
- mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff;
+ mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff;
if (mday == 0xff)
mday = M48T59_READ(M48T59_MDAY);
hour = tm->tm_hour;
- hour = (hour < 24) ? BIN2BCD(hour) : 0x00;
+ hour = (hour < 24) ? bin2bcd(hour) : 0x00;
min = tm->tm_min;
- min = (min < 60) ? BIN2BCD(min) : 0x00;
+ min = (min < 60) ? bin2bcd(min) : 0x00;
sec = tm->tm_sec;
- sec = (sec < 60) ? BIN2BCD(sec) : 0x00;
+ sec = (sec < 60) ? bin2bcd(sec) : 0x00;
spin_lock_irqsave(&m48t59->lock, flags);
/* Issue the WRITE command */
@@ -360,7 +360,6 @@ static struct bin_attribute m48t59_nvram_attr = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.read = m48t59_nvram_read,
.write = m48t59_nvram_write,
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
index 3f7f99a5d96..7c045cffa9f 100644
--- a/drivers/rtc/rtc-m48t86.c
+++ b/drivers/rtc/rtc-m48t86.c
@@ -62,14 +62,14 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_wday = ops->readbyte(M48T86_REG_DOW);
} else {
/* bcd mode */
- tm->tm_sec = BCD2BIN(ops->readbyte(M48T86_REG_SEC));
- tm->tm_min = BCD2BIN(ops->readbyte(M48T86_REG_MIN));
- tm->tm_hour = BCD2BIN(ops->readbyte(M48T86_REG_HOUR) & 0x3F);
- tm->tm_mday = BCD2BIN(ops->readbyte(M48T86_REG_DOM));
+ tm->tm_sec = bcd2bin(ops->readbyte(M48T86_REG_SEC));
+ tm->tm_min = bcd2bin(ops->readbyte(M48T86_REG_MIN));
+ tm->tm_hour = bcd2bin(ops->readbyte(M48T86_REG_HOUR) & 0x3F);
+ tm->tm_mday = bcd2bin(ops->readbyte(M48T86_REG_DOM));
/* tm_mon is 0-11 */
- tm->tm_mon = BCD2BIN(ops->readbyte(M48T86_REG_MONTH)) - 1;
- tm->tm_year = BCD2BIN(ops->readbyte(M48T86_REG_YEAR)) + 100;
- tm->tm_wday = BCD2BIN(ops->readbyte(M48T86_REG_DOW));
+ tm->tm_mon = bcd2bin(ops->readbyte(M48T86_REG_MONTH)) - 1;
+ tm->tm_year = bcd2bin(ops->readbyte(M48T86_REG_YEAR)) + 100;
+ tm->tm_wday = bcd2bin(ops->readbyte(M48T86_REG_DOW));
}
/* correct the hour if the clock is in 12h mode */
@@ -103,13 +103,13 @@ static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)
ops->writebyte(tm->tm_wday, M48T86_REG_DOW);
} else {
/* bcd mode */
- ops->writebyte(BIN2BCD(tm->tm_sec), M48T86_REG_SEC);
- ops->writebyte(BIN2BCD(tm->tm_min), M48T86_REG_MIN);
- ops->writebyte(BIN2BCD(tm->tm_hour), M48T86_REG_HOUR);
- ops->writebyte(BIN2BCD(tm->tm_mday), M48T86_REG_DOM);
- ops->writebyte(BIN2BCD(tm->tm_mon + 1), M48T86_REG_MONTH);
- ops->writebyte(BIN2BCD(tm->tm_year % 100), M48T86_REG_YEAR);
- ops->writebyte(BIN2BCD(tm->tm_wday), M48T86_REG_DOW);
+ ops->writebyte(bin2bcd(tm->tm_sec), M48T86_REG_SEC);
+ ops->writebyte(bin2bcd(tm->tm_min), M48T86_REG_MIN);
+ ops->writebyte(bin2bcd(tm->tm_hour), M48T86_REG_HOUR);
+ ops->writebyte(bin2bcd(tm->tm_mday), M48T86_REG_DOM);
+ ops->writebyte(bin2bcd(tm->tm_mon + 1), M48T86_REG_MONTH);
+ ops->writebyte(bin2bcd(tm->tm_year % 100), M48T86_REG_YEAR);
+ ops->writebyte(bin2bcd(tm->tm_wday), M48T86_REG_DOW);
}
/* update ended */
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index 12c9cd25cad..80782798763 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -150,14 +150,14 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
if (rc < 0)
return rc;
- tm->tm_sec = BCD2BIN(regs[MAX6900_REG_SC]);
- tm->tm_min = BCD2BIN(regs[MAX6900_REG_MN]);
- tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f);
- tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
- tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
- tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
- BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
- tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
+ tm->tm_sec = bcd2bin(regs[MAX6900_REG_SC]);
+ tm->tm_min = bcd2bin(regs[MAX6900_REG_MN]);
+ tm->tm_hour = bcd2bin(regs[MAX6900_REG_HR] & 0x3f);
+ tm->tm_mday = bcd2bin(regs[MAX6900_REG_DT]);
+ tm->tm_mon = bcd2bin(regs[MAX6900_REG_MO]) - 1;
+ tm->tm_year = bcd2bin(regs[MAX6900_REG_YR]) +
+ bcd2bin(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
+ tm->tm_wday = bcd2bin(regs[MAX6900_REG_DW]);
return 0;
}
@@ -184,14 +184,14 @@ max6900_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
if (rc < 0)
return rc;
- regs[MAX6900_REG_SC] = BIN2BCD(tm->tm_sec);
- regs[MAX6900_REG_MN] = BIN2BCD(tm->tm_min);
- regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour);
- regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday);
- regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1);
- regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday);
- regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year % 100);
- regs[MAX6900_REG_CENTURY] = BIN2BCD((tm->tm_year + 1900) / 100);
+ regs[MAX6900_REG_SC] = bin2bcd(tm->tm_sec);
+ regs[MAX6900_REG_MN] = bin2bcd(tm->tm_min);
+ regs[MAX6900_REG_HR] = bin2bcd(tm->tm_hour);
+ regs[MAX6900_REG_DT] = bin2bcd(tm->tm_mday);
+ regs[MAX6900_REG_MO] = bin2bcd(tm->tm_mon + 1);
+ regs[MAX6900_REG_DW] = bin2bcd(tm->tm_wday);
+ regs[MAX6900_REG_YR] = bin2bcd(tm->tm_year % 100);
+ regs[MAX6900_REG_CENTURY] = bin2bcd((tm->tm_year + 1900) / 100);
/* set write protect */
regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index 78b2551fb19..2f6507df7b4 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -124,15 +124,15 @@ static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
/* The chip sends data in this order:
* Seconds, Minutes, Hours, Date, Month, Day, Year */
- dt->tm_sec = BCD2BIN(chip->buf[1]);
- dt->tm_min = BCD2BIN(chip->buf[2]);
- dt->tm_hour = BCD2BIN(chip->buf[3]);
- dt->tm_mday = BCD2BIN(chip->buf[4]);
- dt->tm_mon = BCD2BIN(chip->buf[5]) - 1;
- dt->tm_wday = BCD2BIN(chip->buf[6]);
- dt->tm_year = BCD2BIN(chip->buf[7]);
+ dt->tm_sec = bcd2bin(chip->buf[1]);
+ dt->tm_min = bcd2bin(chip->buf[2]);
+ dt->tm_hour = bcd2bin(chip->buf[3]);
+ dt->tm_mday = bcd2bin(chip->buf[4]);
+ dt->tm_mon = bcd2bin(chip->buf[5]) - 1;
+ dt->tm_wday = bcd2bin(chip->buf[6]);
+ dt->tm_year = bcd2bin(chip->buf[7]);
- century = BCD2BIN(tmp) * 100;
+ century = bcd2bin(tmp) * 100;
dt->tm_year += century;
dt->tm_year -= 1900;
@@ -168,15 +168,15 @@ static int max6902_set_datetime(struct device *dev, struct rtc_time *dt)
/* Remove write protection */
max6902_set_reg(dev, 0xF, 0);
- max6902_set_reg(dev, 0x01, BIN2BCD(dt->tm_sec));
- max6902_set_reg(dev, 0x03, BIN2BCD(dt->tm_min));
- max6902_set_reg(dev, 0x05, BIN2BCD(dt->tm_hour));
+ max6902_set_reg(dev, 0x01, bin2bcd(dt->tm_sec));
+ max6902_set_reg(dev, 0x03, bin2bcd(dt->tm_min));
+ max6902_set_reg(dev, 0x05, bin2bcd(dt->tm_hour));
- max6902_set_reg(dev, 0x07, BIN2BCD(dt->tm_mday));
- max6902_set_reg(dev, 0x09, BIN2BCD(dt->tm_mon+1));
- max6902_set_reg(dev, 0x0B, BIN2BCD(dt->tm_wday));
- max6902_set_reg(dev, 0x0D, BIN2BCD(dt->tm_year%100));
- max6902_set_reg(dev, 0x13, BIN2BCD(dt->tm_year/100));
+ max6902_set_reg(dev, 0x07, bin2bcd(dt->tm_mday));
+ max6902_set_reg(dev, 0x09, bin2bcd(dt->tm_mon+1));
+ max6902_set_reg(dev, 0x0B, bin2bcd(dt->tm_wday));
+ max6902_set_reg(dev, 0x0D, bin2bcd(dt->tm_year%100));
+ max6902_set_reg(dev, 0x13, bin2bcd(dt->tm_year/100));
/* Compulab used a delay here. However, the datasheet
* does not mention a delay being required anywhere... */
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 8876605d4d4..2cbeb0794f1 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -186,30 +186,30 @@ static int tm2bcd(struct rtc_time *tm)
if (rtc_valid_tm(tm) != 0)
return -EINVAL;
- tm->tm_sec = BIN2BCD(tm->tm_sec);
- tm->tm_min = BIN2BCD(tm->tm_min);
- tm->tm_hour = BIN2BCD(tm->tm_hour);
- tm->tm_mday = BIN2BCD(tm->tm_mday);
+ tm->tm_sec = bin2bcd(tm->tm_sec);
+ tm->tm_min = bin2bcd(tm->tm_min);
+ tm->tm_hour = bin2bcd(tm->tm_hour);
+ tm->tm_mday = bin2bcd(tm->tm_mday);
- tm->tm_mon = BIN2BCD(tm->tm_mon + 1);
+ tm->tm_mon = bin2bcd(tm->tm_mon + 1);
/* epoch == 1900 */
if (tm->tm_year < 100 || tm->tm_year > 199)
return -EINVAL;
- tm->tm_year = BIN2BCD(tm->tm_year - 100);
+ tm->tm_year = bin2bcd(tm->tm_year - 100);
return 0;
}
static void bcd2tm(struct rtc_time *tm)
{
- tm->tm_sec = BCD2BIN(tm->tm_sec);
- tm->tm_min = BCD2BIN(tm->tm_min);
- tm->tm_hour = BCD2BIN(tm->tm_hour);
- tm->tm_mday = BCD2BIN(tm->tm_mday);
- tm->tm_mon = BCD2BIN(tm->tm_mon) - 1;
+ tm->tm_sec = bcd2bin(tm->tm_sec);
+ tm->tm_min = bcd2bin(tm->tm_min);
+ tm->tm_hour = bcd2bin(tm->tm_hour);
+ tm->tm_mday = bcd2bin(tm->tm_mday);
+ tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
/* epoch == 1900 */
- tm->tm_year = BCD2BIN(tm->tm_year) + 100;
+ tm->tm_year = bcd2bin(tm->tm_year) + 100;
}
diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c
new file mode 100644
index 00000000000..346d633655e
--- /dev/null
+++ b/drivers/rtc/rtc-parisc.c
@@ -0,0 +1,111 @@
+/* rtc-parisc: RTC for HP PA-RISC firmware
+ *
+ * Copyright (C) 2008 Kyle McMartin <kyle@mcmartin.ca>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+
+#include <asm/rtc.h>
+
+/* as simple as can be, and no simpler. */
+struct parisc_rtc {
+ struct rtc_device *rtc;
+ spinlock_t lock;
+};
+
+static int parisc_get_time(struct device *dev, struct rtc_time *tm)
+{
+ struct parisc_rtc *p = dev_get_drvdata(dev);
+ unsigned long flags, ret;
+
+ spin_lock_irqsave(&p->lock, flags);
+ ret = get_rtc_time(tm);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ if (ret & RTC_BATT_BAD)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int parisc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct parisc_rtc *p = dev_get_drvdata(dev);
+ unsigned long flags, ret;
+
+ spin_lock_irqsave(&p->lock, flags);
+ ret = set_rtc_time(tm);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ if (ret < 0)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static const struct rtc_class_ops parisc_rtc_ops = {
+ .read_time = parisc_get_time,
+ .set_time = parisc_set_time,
+};
+
+static int __devinit parisc_rtc_probe(struct platform_device *dev)
+{
+ struct parisc_rtc *p;
+
+ p = kzalloc(sizeof (*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ spin_lock_init(&p->lock);
+
+ p->rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(p->rtc)) {
+ int err = PTR_ERR(p->rtc);
+ kfree(p);
+ return err;
+ }
+
+ platform_set_drvdata(dev, p);
+
+ return 0;
+}
+
+static int __devexit parisc_rtc_remove(struct platform_device *dev)
+{
+ struct parisc_rtc *p = platform_get_drvdata(dev);
+
+ rtc_device_unregister(p->rtc);
+ kfree(p);
+
+ return 0;
+}
+
+static struct platform_driver parisc_rtc_driver = {
+ .driver = {
+ .name = "rtc-parisc",
+ .owner = THIS_MODULE,
+ },
+ .probe = parisc_rtc_probe,
+ .remove = __devexit_p(parisc_rtc_remove),
+};
+
+static int __init parisc_rtc_init(void)
+{
+ return platform_driver_register(&parisc_rtc_driver);
+}
+
+static void __exit parisc_rtc_fini(void)
+{
+ platform_driver_unregister(&parisc_rtc_driver);
+}
+
+module_init(parisc_rtc_init);
+module_exit(parisc_rtc_fini);
+
+MODULE_AUTHOR("Kyle McMartin <kyle@mcmartin.ca>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HP PA-RISC RTC driver");
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index a829f20ad6d..b725913ccbe 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -97,13 +97,13 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
buf[8]);
- tm->tm_sec = BCD2BIN(buf[PCF8563_REG_SC] & 0x7F);
- tm->tm_min = BCD2BIN(buf[PCF8563_REG_MN] & 0x7F);
- tm->tm_hour = BCD2BIN(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
- tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F);
+ tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
+ tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
+ tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F);
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
- tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
- tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]);
+ tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
+ tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
if (tm->tm_year < 70)
tm->tm_year += 100; /* assume we are in 1970...2069 */
/* detect the polarity heuristically. see note above. */
@@ -138,17 +138,17 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
/* hours, minutes and seconds */
- buf[PCF8563_REG_SC] = BIN2BCD(tm->tm_sec);
- buf[PCF8563_REG_MN] = BIN2BCD(tm->tm_min);
- buf[PCF8563_REG_HR] = BIN2BCD(tm->tm_hour);
+ buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);
+ buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);
+ buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);
- buf[PCF8563_REG_DM] = BIN2BCD(tm->tm_mday);
+ buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);
/* month, 1 - 12 */
- buf[PCF8563_REG_MO] = BIN2BCD(tm->tm_mon + 1);
+ buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);
/* year and century */
- buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100);
+ buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);
if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index d388c662bf4..7d33cda3f8f 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -76,11 +76,11 @@ static int pcf8583_get_datetime(struct i2c_client *client, struct rtc_time *dt)
buf[4] &= 0x3f;
buf[5] &= 0x1f;
- dt->tm_sec = BCD2BIN(buf[1]);
- dt->tm_min = BCD2BIN(buf[2]);
- dt->tm_hour = BCD2BIN(buf[3]);
- dt->tm_mday = BCD2BIN(buf[4]);
- dt->tm_mon = BCD2BIN(buf[5]) - 1;
+ dt->tm_sec = bcd2bin(buf[1]);
+ dt->tm_min = bcd2bin(buf[2]);
+ dt->tm_hour = bcd2bin(buf[3]);
+ dt->tm_mday = bcd2bin(buf[4]);
+ dt->tm_mon = bcd2bin(buf[5]) - 1;
}
return ret == 2 ? 0 : -EIO;
@@ -94,14 +94,14 @@ static int pcf8583_set_datetime(struct i2c_client *client, struct rtc_time *dt,
buf[0] = 0;
buf[1] = get_ctrl(client) | 0x80;
buf[2] = 0;
- buf[3] = BIN2BCD(dt->tm_sec);
- buf[4] = BIN2BCD(dt->tm_min);
- buf[5] = BIN2BCD(dt->tm_hour);
+ buf[3] = bin2bcd(dt->tm_sec);
+ buf[4] = bin2bcd(dt->tm_min);
+ buf[5] = bin2bcd(dt->tm_hour);
if (datetoo) {
len = 8;
- buf[6] = BIN2BCD(dt->tm_mday) | (dt->tm_year << 6);
- buf[7] = BIN2BCD(dt->tm_mon + 1) | (dt->tm_wday << 5);
+ buf[6] = bin2bcd(dt->tm_mday) | (dt->tm_year << 6);
+ buf[7] = bin2bcd(dt->tm_mon + 1) | (dt->tm_wday << 5);
}
ret = i2c_master_send(client, (char *)buf, len);
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
index 395985b339c..42028f233be 100644
--- a/drivers/rtc/rtc-r9701.c
+++ b/drivers/rtc/rtc-r9701.c
@@ -80,13 +80,13 @@ static int r9701_get_datetime(struct device *dev, struct rtc_time *dt)
memset(dt, 0, sizeof(*dt));
- dt->tm_sec = BCD2BIN(buf[0]); /* RSECCNT */
- dt->tm_min = BCD2BIN(buf[1]); /* RMINCNT */
- dt->tm_hour = BCD2BIN(buf[2]); /* RHRCNT */
+ dt->tm_sec = bcd2bin(buf[0]); /* RSECCNT */
+ dt->tm_min = bcd2bin(buf[1]); /* RMINCNT */
+ dt->tm_hour = bcd2bin(buf[2]); /* RHRCNT */
- dt->tm_mday = BCD2BIN(buf[3]); /* RDAYCNT */
- dt->tm_mon = BCD2BIN(buf[4]) - 1; /* RMONCNT */
- dt->tm_year = BCD2BIN(buf[5]) + 100; /* RYRCNT */
+ dt->tm_mday = bcd2bin(buf[3]); /* RDAYCNT */
+ dt->tm_mon = bcd2bin(buf[4]) - 1; /* RMONCNT */
+ dt->tm_year = bcd2bin(buf[5]) + 100; /* RYRCNT */
/* the rtc device may contain illegal values on power up
* according to the data sheet. make sure they are valid.
@@ -103,12 +103,12 @@ static int r9701_set_datetime(struct device *dev, struct rtc_time *dt)
if (year >= 2100 || year < 2000)
return -EINVAL;
- ret = write_reg(dev, RHRCNT, BIN2BCD(dt->tm_hour));
- ret = ret ? ret : write_reg(dev, RMINCNT, BIN2BCD(dt->tm_min));
- ret = ret ? ret : write_reg(dev, RSECCNT, BIN2BCD(dt->tm_sec));
- ret = ret ? ret : write_reg(dev, RDAYCNT, BIN2BCD(dt->tm_mday));
- ret = ret ? ret : write_reg(dev, RMONCNT, BIN2BCD(dt->tm_mon + 1));
- ret = ret ? ret : write_reg(dev, RYRCNT, BIN2BCD(dt->tm_year - 100));
+ ret = write_reg(dev, RHRCNT, bin2bcd(dt->tm_hour));
+ ret = ret ? ret : write_reg(dev, RMINCNT, bin2bcd(dt->tm_min));
+ ret = ret ? ret : write_reg(dev, RSECCNT, bin2bcd(dt->tm_sec));
+ ret = ret ? ret : write_reg(dev, RDAYCNT, bin2bcd(dt->tm_mday));
+ ret = ret ? ret : write_reg(dev, RMONCNT, bin2bcd(dt->tm_mon + 1));
+ ret = ret ? ret : write_reg(dev, RYRCNT, bin2bcd(dt->tm_year - 100));
ret = ret ? ret : write_reg(dev, RWKCNT, 1 << dt->tm_wday);
return ret;
diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c
index 1c14d4497c4..e6ea3f5ee1e 100644
--- a/drivers/rtc/rtc-rs5c313.c
+++ b/drivers/rtc/rtc-rs5c313.c
@@ -235,33 +235,33 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
data = rs5c313_read_reg(RS5C313_ADDR_SEC);
data |= (rs5c313_read_reg(RS5C313_ADDR_SEC10) << 4);
- tm->tm_sec = BCD2BIN(data);
+ tm->tm_sec = bcd2bin(data);
data = rs5c313_read_reg(RS5C313_ADDR_MIN);
data |= (rs5c313_read_reg(RS5C313_ADDR_MIN10) << 4);
- tm->tm_min = BCD2BIN(data);
+ tm->tm_min = bcd2bin(data);
data = rs5c313_read_reg(RS5C313_ADDR_HOUR);
data |= (rs5c313_read_reg(RS5C313_ADDR_HOUR10) << 4);
- tm->tm_hour = BCD2BIN(data);
+ tm->tm_hour = bcd2bin(data);
data = rs5c313_read_reg(RS5C313_ADDR_DAY);
data |= (rs5c313_read_reg(RS5C313_ADDR_DAY10) << 4);
- tm->tm_mday = BCD2BIN(data);
+ tm->tm_mday = bcd2bin(data);
data = rs5c313_read_reg(RS5C313_ADDR_MON);
data |= (rs5c313_read_reg(RS5C313_ADDR_MON10) << 4);
- tm->tm_mon = BCD2BIN(data) - 1;
+ tm->tm_mon = bcd2bin(data) - 1;
data = rs5c313_read_reg(RS5C313_ADDR_YEAR);
data |= (rs5c313_read_reg(RS5C313_ADDR_YEAR10) << 4);
- tm->tm_year = BCD2BIN(data);
+ tm->tm_year = bcd2bin(data);
if (tm->tm_year < 70)
tm->tm_year += 100;
data = rs5c313_read_reg(RS5C313_ADDR_WEEK);
- tm->tm_wday = BCD2BIN(data);
+ tm->tm_wday = bcd2bin(data);
RS5C313_CEDISABLE;
ndelay(700); /* CE:L */
@@ -294,31 +294,31 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
}
}
- data = BIN2BCD(tm->tm_sec);
+ data = bin2bcd(tm->tm_sec);
rs5c313_write_reg(RS5C313_ADDR_SEC, data);
rs5c313_write_reg(RS5C313_ADDR_SEC10, (data >> 4));
- data = BIN2BCD(tm->tm_min);
+ data = bin2bcd(tm->tm_min);
rs5c313_write_reg(RS5C313_ADDR_MIN, data );
rs5c313_write_reg(RS5C313_ADDR_MIN10, (data >> 4));
- data = BIN2BCD(tm->tm_hour);
+ data = bin2bcd(tm->tm_hour);
rs5c313_write_reg(RS5C313_ADDR_HOUR, data);
rs5c313_write_reg(RS5C313_ADDR_HOUR10, (data >> 4));
- data = BIN2BCD(tm->tm_mday);
+ data = bin2bcd(tm->tm_mday);
rs5c313_write_reg(RS5C313_ADDR_DAY, data);
rs5c313_write_reg(RS5C313_ADDR_DAY10, (data>> 4));
- data = BIN2BCD(tm->tm_mon + 1);
+ data = bin2bcd(tm->tm_mon + 1);
rs5c313_write_reg(RS5C313_ADDR_MON, data);
rs5c313_write_reg(RS5C313_ADDR_MON10, (data >> 4));
- data = BIN2BCD(tm->tm_year % 100);
+ data = bin2bcd(tm->tm_year % 100);
rs5c313_write_reg(RS5C313_ADDR_YEAR, data);
rs5c313_write_reg(RS5C313_ADDR_YEAR10, (data >> 4));
- data = BIN2BCD(tm->tm_wday);
+ data = bin2bcd(tm->tm_wday);
rs5c313_write_reg(RS5C313_ADDR_WEEK, data);
RS5C313_CEDISABLE; /* CE:H */
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index 839462659af..dd1e2bc7a47 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -74,20 +74,20 @@ rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm)
txbuf[3] = 0; /* dummy */
txbuf[4] = RS5C348_CMD_MW(RS5C348_REG_SECS); /* cmd, sec, ... */
txp = &txbuf[5];
- txp[RS5C348_REG_SECS] = BIN2BCD(tm->tm_sec);
- txp[RS5C348_REG_MINS] = BIN2BCD(tm->tm_min);
+ txp[RS5C348_REG_SECS] = bin2bcd(tm->tm_sec);
+ txp[RS5C348_REG_MINS] = bin2bcd(tm->tm_min);
if (pdata->rtc_24h) {
- txp[RS5C348_REG_HOURS] = BIN2BCD(tm->tm_hour);
+ txp[RS5C348_REG_HOURS] = bin2bcd(tm->tm_hour);
} else {
/* hour 0 is AM12, noon is PM12 */
- txp[RS5C348_REG_HOURS] = BIN2BCD((tm->tm_hour + 11) % 12 + 1) |
+ txp[RS5C348_REG_HOURS] = bin2bcd((tm->tm_hour + 11) % 12 + 1) |
(tm->tm_hour >= 12 ? RS5C348_BIT_PM : 0);
}
- txp[RS5C348_REG_WDAY] = BIN2BCD(tm->tm_wday);
- txp[RS5C348_REG_DAY] = BIN2BCD(tm->tm_mday);
- txp[RS5C348_REG_MONTH] = BIN2BCD(tm->tm_mon + 1) |
+ txp[RS5C348_REG_WDAY] = bin2bcd(tm->tm_wday);
+ txp[RS5C348_REG_DAY] = bin2bcd(tm->tm_mday);
+ txp[RS5C348_REG_MONTH] = bin2bcd(tm->tm_mon + 1) |
(tm->tm_year >= 100 ? RS5C348_BIT_Y2K : 0);
- txp[RS5C348_REG_YEAR] = BIN2BCD(tm->tm_year % 100);
+ txp[RS5C348_REG_YEAR] = bin2bcd(tm->tm_year % 100);
/* write in one transfer to avoid data inconsistency */
ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), NULL, 0);
udelay(62); /* Tcsr 62us */
@@ -116,20 +116,20 @@ rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (ret < 0)
return ret;
- tm->tm_sec = BCD2BIN(rxbuf[RS5C348_REG_SECS] & RS5C348_SECS_MASK);
- tm->tm_min = BCD2BIN(rxbuf[RS5C348_REG_MINS] & RS5C348_MINS_MASK);
- tm->tm_hour = BCD2BIN(rxbuf[RS5C348_REG_HOURS] & RS5C348_HOURS_MASK);
+ tm->tm_sec = bcd2bin(rxbuf[RS5C348_REG_SECS] & RS5C348_SECS_MASK);
+ tm->tm_min = bcd2bin(rxbuf[RS5C348_REG_MINS] & RS5C348_MINS_MASK);
+ tm->tm_hour = bcd2bin(rxbuf[RS5C348_REG_HOURS] & RS5C348_HOURS_MASK);
if (!pdata->rtc_24h) {
tm->tm_hour %= 12;
if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM)
tm->tm_hour += 12;
}
- tm->tm_wday = BCD2BIN(rxbuf[RS5C348_REG_WDAY] & RS5C348_WDAY_MASK);
- tm->tm_mday = BCD2BIN(rxbuf[RS5C348_REG_DAY] & RS5C348_DAY_MASK);
+ tm->tm_wday = bcd2bin(rxbuf[RS5C348_REG_WDAY] & RS5C348_WDAY_MASK);
+ tm->tm_mday = bcd2bin(rxbuf[RS5C348_REG_DAY] & RS5C348_DAY_MASK);
tm->tm_mon =
- BCD2BIN(rxbuf[RS5C348_REG_MONTH] & RS5C348_MONTH_MASK) - 1;
+ bcd2bin(rxbuf[RS5C348_REG_MONTH] & RS5C348_MONTH_MASK) - 1;
/* year is 1900 + tm->tm_year */
- tm->tm_year = BCD2BIN(rxbuf[RS5C348_REG_YEAR]) +
+ tm->tm_year = bcd2bin(rxbuf[RS5C348_REG_YEAR]) +
((rxbuf[RS5C348_REG_MONTH] & RS5C348_BIT_Y2K) ? 100 : 0);
if (rtc_valid_tm(tm) < 0) {
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 8b561958fb1..2f2c68d476d 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -148,9 +148,9 @@ static unsigned rs5c_reg2hr(struct rs5c372 *rs5c, unsigned reg)
unsigned hour;
if (rs5c->time24)
- return BCD2BIN(reg & 0x3f);
+ return bcd2bin(reg & 0x3f);
- hour = BCD2BIN(reg & 0x1f);
+ hour = bcd2bin(reg & 0x1f);
if (hour == 12)
hour = 0;
if (reg & 0x20)
@@ -161,15 +161,15 @@ static unsigned rs5c_reg2hr(struct rs5c372 *rs5c, unsigned reg)
static unsigned rs5c_hr2reg(struct rs5c372 *rs5c, unsigned hour)
{
if (rs5c->time24)
- return BIN2BCD(hour);
+ return bin2bcd(hour);
if (hour > 12)
- return 0x20 | BIN2BCD(hour - 12);
+ return 0x20 | bin2bcd(hour - 12);
if (hour == 12)
- return 0x20 | BIN2BCD(12);
+ return 0x20 | bin2bcd(12);
if (hour == 0)
- return BIN2BCD(12);
- return BIN2BCD(hour);
+ return bin2bcd(12);
+ return bin2bcd(hour);
}
static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
@@ -180,18 +180,18 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
if (status < 0)
return status;
- tm->tm_sec = BCD2BIN(rs5c->regs[RS5C372_REG_SECS] & 0x7f);
- tm->tm_min = BCD2BIN(rs5c->regs[RS5C372_REG_MINS] & 0x7f);
+ tm->tm_sec = bcd2bin(rs5c->regs[RS5C372_REG_SECS] & 0x7f);
+ tm->tm_min = bcd2bin(rs5c->regs[RS5C372_REG_MINS] & 0x7f);
tm->tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C372_REG_HOURS]);
- tm->tm_wday = BCD2BIN(rs5c->regs[RS5C372_REG_WDAY] & 0x07);
- tm->tm_mday = BCD2BIN(rs5c->regs[RS5C372_REG_DAY] & 0x3f);
+ tm->tm_wday = bcd2bin(rs5c->regs[RS5C372_REG_WDAY] & 0x07);
+ tm->tm_mday = bcd2bin(rs5c->regs[RS5C372_REG_DAY] & 0x3f);
/* tm->tm_mon is zero-based */
- tm->tm_mon = BCD2BIN(rs5c->regs[RS5C372_REG_MONTH] & 0x1f) - 1;
+ tm->tm_mon = bcd2bin(rs5c->regs[RS5C372_REG_MONTH] & 0x1f) - 1;
/* year is 1900 + tm->tm_year */
- tm->tm_year = BCD2BIN(rs5c->regs[RS5C372_REG_YEAR]) + 100;
+ tm->tm_year = bcd2bin(rs5c->regs[RS5C372_REG_YEAR]) + 100;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -216,13 +216,13 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
addr = RS5C_ADDR(RS5C372_REG_SECS);
- buf[0] = BIN2BCD(tm->tm_sec);
- buf[1] = BIN2BCD(tm->tm_min);
+ buf[0] = bin2bcd(tm->tm_sec);
+ buf[1] = bin2bcd(tm->tm_min);
buf[2] = rs5c_hr2reg(rs5c, tm->tm_hour);
- buf[3] = BIN2BCD(tm->tm_wday);
- buf[4] = BIN2BCD(tm->tm_mday);
- buf[5] = BIN2BCD(tm->tm_mon + 1);
- buf[6] = BIN2BCD(tm->tm_year - 100);
+ buf[3] = bin2bcd(tm->tm_wday);
+ buf[4] = bin2bcd(tm->tm_mday);
+ buf[5] = bin2bcd(tm->tm_mon + 1);
+ buf[6] = bin2bcd(tm->tm_year - 100);
if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
@@ -367,7 +367,7 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t)
/* report alarm time */
t->time.tm_sec = 0;
- t->time.tm_min = BCD2BIN(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
+ t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
t->time.tm_mday = -1;
t->time.tm_mon = -1;
@@ -413,7 +413,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
}
/* set alarm */
- buf[0] = BIN2BCD(t->time.tm_min);
+ buf[0] = bin2bcd(t->time.tm_min);
buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
buf[2] = 0x7f; /* any/all days */
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index a6fa1f2f2ca..def4d396d0b 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -104,12 +104,12 @@ static int s35390a_disable_test_mode(struct s35390a *s35390a)
static char s35390a_hr2reg(struct s35390a *s35390a, int hour)
{
if (s35390a->twentyfourhour)
- return BIN2BCD(hour);
+ return bin2bcd(hour);
if (hour < 12)
- return BIN2BCD(hour);
+ return bin2bcd(hour);
- return 0x40 | BIN2BCD(hour - 12);
+ return 0x40 | bin2bcd(hour - 12);
}
static int s35390a_reg2hr(struct s35390a *s35390a, char reg)
@@ -117,9 +117,9 @@ static int s35390a_reg2hr(struct s35390a *s35390a, char reg)
unsigned hour;
if (s35390a->twentyfourhour)
- return BCD2BIN(reg & 0x3f);
+ return bcd2bin(reg & 0x3f);
- hour = BCD2BIN(reg & 0x3f);
+ hour = bcd2bin(reg & 0x3f);
if (reg & 0x40)
hour += 12;
@@ -137,13 +137,13 @@ static int s35390a_set_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year,
tm->tm_wday);
- buf[S35390A_BYTE_YEAR] = BIN2BCD(tm->tm_year - 100);
- buf[S35390A_BYTE_MONTH] = BIN2BCD(tm->tm_mon + 1);
- buf[S35390A_BYTE_DAY] = BIN2BCD(tm->tm_mday);
- buf[S35390A_BYTE_WDAY] = BIN2BCD(tm->tm_wday);
+ buf[S35390A_BYTE_YEAR] = bin2bcd(tm->tm_year - 100);
+ buf[S35390A_BYTE_MONTH] = bin2bcd(tm->tm_mon + 1);
+ buf[S35390A_BYTE_DAY] = bin2bcd(tm->tm_mday);
+ buf[S35390A_BYTE_WDAY] = bin2bcd(tm->tm_wday);
buf[S35390A_BYTE_HOURS] = s35390a_hr2reg(s35390a, tm->tm_hour);
- buf[S35390A_BYTE_MINS] = BIN2BCD(tm->tm_min);
- buf[S35390A_BYTE_SECS] = BIN2BCD(tm->tm_sec);
+ buf[S35390A_BYTE_MINS] = bin2bcd(tm->tm_min);
+ buf[S35390A_BYTE_SECS] = bin2bcd(tm->tm_sec);
/* This chip expects the bits of each byte to be in reverse order */
for (i = 0; i < 7; ++i)
@@ -168,13 +168,13 @@ static int s35390a_get_datetime(struct i2c_client *client, struct rtc_time *tm)
for (i = 0; i < 7; ++i)
buf[i] = bitrev8(buf[i]);
- tm->tm_sec = BCD2BIN(buf[S35390A_BYTE_SECS]);
- tm->tm_min = BCD2BIN(buf[S35390A_BYTE_MINS]);
+ tm->tm_sec = bcd2bin(buf[S35390A_BYTE_SECS]);
+ tm->tm_min = bcd2bin(buf[S35390A_BYTE_MINS]);
tm->tm_hour = s35390a_reg2hr(s35390a, buf[S35390A_BYTE_HOURS]);
- tm->tm_wday = BCD2BIN(buf[S35390A_BYTE_WDAY]);
- tm->tm_mday = BCD2BIN(buf[S35390A_BYTE_DAY]);
- tm->tm_mon = BCD2BIN(buf[S35390A_BYTE_MONTH]) - 1;
- tm->tm_year = BCD2BIN(buf[S35390A_BYTE_YEAR]) + 100;
+ tm->tm_wday = bcd2bin(buf[S35390A_BYTE_WDAY]);
+ tm->tm_mday = bcd2bin(buf[S35390A_BYTE_DAY]);
+ tm->tm_mon = bcd2bin(buf[S35390A_BYTE_MONTH]) - 1;
+ tm->tm_year = bcd2bin(buf[S35390A_BYTE_YEAR]) + 100;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, mday=%d, "
"mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec,
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index e7d19b6c265..910bc704939 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -134,12 +134,12 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
- BCD_TO_BIN(rtc_tm->tm_sec);
- BCD_TO_BIN(rtc_tm->tm_min);
- BCD_TO_BIN(rtc_tm->tm_hour);
- BCD_TO_BIN(rtc_tm->tm_mday);
- BCD_TO_BIN(rtc_tm->tm_mon);
- BCD_TO_BIN(rtc_tm->tm_year);
+ rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
+ rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
+ rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
+ rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
+ rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
+ rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
rtc_tm->tm_year += 100;
rtc_tm->tm_mon -= 1;
@@ -163,12 +163,12 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
return -EINVAL;
}
- writeb(BIN2BCD(tm->tm_sec), base + S3C2410_RTCSEC);
- writeb(BIN2BCD(tm->tm_min), base + S3C2410_RTCMIN);
- writeb(BIN2BCD(tm->tm_hour), base + S3C2410_RTCHOUR);
- writeb(BIN2BCD(tm->tm_mday), base + S3C2410_RTCDATE);
- writeb(BIN2BCD(tm->tm_mon + 1), base + S3C2410_RTCMON);
- writeb(BIN2BCD(year), base + S3C2410_RTCYEAR);
+ writeb(bin2bcd(tm->tm_sec), base + S3C2410_RTCSEC);
+ writeb(bin2bcd(tm->tm_min), base + S3C2410_RTCMIN);
+ writeb(bin2bcd(tm->tm_hour), base + S3C2410_RTCHOUR);
+ writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE);
+ writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON);
+ writeb(bin2bcd(year), base + S3C2410_RTCYEAR);
return 0;
}
@@ -199,34 +199,34 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
/* decode the alarm enable field */
if (alm_en & S3C2410_RTCALM_SECEN)
- BCD_TO_BIN(alm_tm->tm_sec);
+ alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
else
alm_tm->tm_sec = 0xff;
if (alm_en & S3C2410_RTCALM_MINEN)
- BCD_TO_BIN(alm_tm->tm_min);
+ alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
else
alm_tm->tm_min = 0xff;
if (alm_en & S3C2410_RTCALM_HOUREN)
- BCD_TO_BIN(alm_tm->tm_hour);
+ alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
else
alm_tm->tm_hour = 0xff;
if (alm_en & S3C2410_RTCALM_DAYEN)
- BCD_TO_BIN(alm_tm->tm_mday);
+ alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
else
alm_tm->tm_mday = 0xff;
if (alm_en & S3C2410_RTCALM_MONEN) {
- BCD_TO_BIN(alm_tm->tm_mon);
+ alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
alm_tm->tm_mon -= 1;
} else {
alm_tm->tm_mon = 0xff;
}
if (alm_en & S3C2410_RTCALM_YEAREN)
- BCD_TO_BIN(alm_tm->tm_year);
+ alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
else
alm_tm->tm_year = 0xffff;
@@ -250,17 +250,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
alrm_en |= S3C2410_RTCALM_SECEN;
- writeb(BIN2BCD(tm->tm_sec), base + S3C2410_ALMSEC);
+ writeb(bin2bcd(tm->tm_sec), base + S3C2410_ALMSEC);
}
if (tm->tm_min < 60 && tm->tm_min >= 0) {
alrm_en |= S3C2410_RTCALM_MINEN;
- writeb(BIN2BCD(tm->tm_min), base + S3C2410_ALMMIN);
+ writeb(bin2bcd(tm->tm_min), base + S3C2410_ALMMIN);
}
if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
alrm_en |= S3C2410_RTCALM_HOUREN;
- writeb(BIN2BCD(tm->tm_hour), base + S3C2410_ALMHOUR);
+ writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR);
}
pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index fcead4c4cd1..aaf9d6a337c 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -324,23 +324,23 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
sec128 = readb(rtc->regbase + R64CNT);
- tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT));
- tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT));
- tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT));
- tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT));
- tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT));
- tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1;
+ tm->tm_sec = bcd2bin(readb(rtc->regbase + RSECCNT));
+ tm->tm_min = bcd2bin(readb(rtc->regbase + RMINCNT));
+ tm->tm_hour = bcd2bin(readb(rtc->regbase + RHRCNT));
+ tm->tm_wday = bcd2bin(readb(rtc->regbase + RWKCNT));
+ tm->tm_mday = bcd2bin(readb(rtc->regbase + RDAYCNT));
+ tm->tm_mon = bcd2bin(readb(rtc->regbase + RMONCNT)) - 1;
if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
yr = readw(rtc->regbase + RYRCNT);
- yr100 = BCD2BIN(yr >> 8);
+ yr100 = bcd2bin(yr >> 8);
yr &= 0xff;
} else {
yr = readb(rtc->regbase + RYRCNT);
- yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
+ yr100 = bcd2bin((yr == 0x99) ? 0x19 : 0x20);
}
- tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;
+ tm->tm_year = (yr100 * 100 + bcd2bin(yr)) - 1900;
sec2 = readb(rtc->regbase + R64CNT);
cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF;
@@ -382,20 +382,20 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
tmp &= ~RCR2_START;
writeb(tmp, rtc->regbase + RCR2);
- writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT);
- writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT);
- writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT);
- writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT);
- writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
- writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT);
+ writeb(bin2bcd(tm->tm_sec), rtc->regbase + RSECCNT);
+ writeb(bin2bcd(tm->tm_min), rtc->regbase + RMINCNT);
+ writeb(bin2bcd(tm->tm_hour), rtc->regbase + RHRCNT);
+ writeb(bin2bcd(tm->tm_wday), rtc->regbase + RWKCNT);
+ writeb(bin2bcd(tm->tm_mday), rtc->regbase + RDAYCNT);
+ writeb(bin2bcd(tm->tm_mon + 1), rtc->regbase + RMONCNT);
if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
- year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
- BIN2BCD(tm->tm_year % 100);
+ year = (bin2bcd((tm->tm_year + 1900) / 100) << 8) |
+ bin2bcd(tm->tm_year % 100);
writew(year, rtc->regbase + RYRCNT);
} else {
year = tm->tm_year % 100;
- writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
+ writeb(bin2bcd(year), rtc->regbase + RYRCNT);
}
/* Start RTC */
@@ -417,7 +417,7 @@ static inline int sh_rtc_read_alarm_value(struct sh_rtc *rtc, int reg_off)
byte = readb(rtc->regbase + reg_off);
if (byte & AR_ENB) {
byte &= ~AR_ENB; /* strip the enable bit */
- value = BCD2BIN(byte);
+ value = bcd2bin(byte);
}
return value;
@@ -455,7 +455,7 @@ static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc,
if (value < 0)
writeb(0, rtc->regbase + reg_off);
else
- writeb(BIN2BCD(value) | AR_ENB, rtc->regbase + reg_off);
+ writeb(bin2bcd(value) | AR_ENB, rtc->regbase + reg_off);
}
static int sh_rtc_check_alarm(struct rtc_time *tm)
@@ -568,7 +568,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
struct sh_rtc *rtc;
struct resource *res;
unsigned int tmp;
- int ret = -ENOENT;
+ int ret;
rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL);
if (unlikely(!rtc))
@@ -577,26 +577,33 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
spin_lock_init(&rtc->lock);
/* get periodic/carry/alarm irqs */
- rtc->periodic_irq = platform_get_irq(pdev, 0);
- if (unlikely(rtc->periodic_irq < 0)) {
+ ret = platform_get_irq(pdev, 0);
+ if (unlikely(ret < 0)) {
+ ret = -ENOENT;
dev_err(&pdev->dev, "No IRQ for period\n");
goto err_badres;
}
+ rtc->periodic_irq = ret;
- rtc->carry_irq = platform_get_irq(pdev, 1);
- if (unlikely(rtc->carry_irq < 0)) {
+ ret = platform_get_irq(pdev, 1);
+ if (unlikely(ret < 0)) {
+ ret = -ENOENT;
dev_err(&pdev->dev, "No IRQ for carry\n");
goto err_badres;
}
+ rtc->carry_irq = ret;
- rtc->alarm_irq = platform_get_irq(pdev, 2);
- if (unlikely(rtc->alarm_irq < 0)) {
+ ret = platform_get_irq(pdev, 2);
+ if (unlikely(ret < 0)) {
+ ret = -ENOENT;
dev_err(&pdev->dev, "No IRQ for alarm\n");
goto err_badres;
}
+ rtc->alarm_irq = ret;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (unlikely(res == NULL)) {
+ ret = -ENOENT;
dev_err(&pdev->dev, "No IO resource\n");
goto err_badres;
}
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 9a7e920315f..f4cd46e15af 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -82,14 +82,14 @@ static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
flags = readb(pdata->ioaddr + RTC_FLAGS);
writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
- writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
- writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
- writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
- writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
- writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
- writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
- writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
- writeb(BIN2BCD((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY);
+ writeb(bin2bcd(tm->tm_year % 100), ioaddr + RTC_YEAR);
+ writeb(bin2bcd(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+ writeb(bin2bcd(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+ writeb(bin2bcd(tm->tm_mday), ioaddr + RTC_DATE);
+ writeb(bin2bcd(tm->tm_hour), ioaddr + RTC_HOURS);
+ writeb(bin2bcd(tm->tm_min), ioaddr + RTC_MINUTES);
+ writeb(bin2bcd(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+ writeb(bin2bcd((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY);
writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
return 0;
@@ -120,14 +120,14 @@ static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm)
year = readb(ioaddr + RTC_YEAR);
century = readb(ioaddr + RTC_CENTURY);
writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS);
- tm->tm_sec = BCD2BIN(second);
- tm->tm_min = BCD2BIN(minute);
- tm->tm_hour = BCD2BIN(hour);
- tm->tm_mday = BCD2BIN(day);
- tm->tm_wday = BCD2BIN(week);
- tm->tm_mon = BCD2BIN(month) - 1;
+ tm->tm_sec = bcd2bin(second);
+ tm->tm_min = bcd2bin(minute);
+ tm->tm_hour = bcd2bin(hour);
+ tm->tm_mday = bcd2bin(day);
+ tm->tm_wday = bcd2bin(week);
+ tm->tm_mon = bcd2bin(month) - 1;
/* year is 1900 + tm->tm_year */
- tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+ tm->tm_year = bcd2bin(year) + bcd2bin(century) * 100 - 1900;
if (rtc_valid_tm(tm) < 0) {
dev_err(dev, "retrieved date/time is not valid.\n");
@@ -148,16 +148,16 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_mday),
+ 0x80 : bin2bcd(pdata->alrm_mday),
ioaddr + RTC_DATE_ALARM);
writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_hour),
+ 0x80 : bin2bcd(pdata->alrm_hour),
ioaddr + RTC_HOURS_ALARM);
writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_min),
+ 0x80 : bin2bcd(pdata->alrm_min),
ioaddr + RTC_MINUTES_ALARM);
writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : BIN2BCD(pdata->alrm_sec),
+ 0x80 : bin2bcd(pdata->alrm_sec),
ioaddr + RTC_SECONDS_ALARM);
writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
readb(ioaddr + RTC_FLAGS); /* clear interrupts */
@@ -280,7 +280,6 @@ static struct bin_attribute stk17ta8_nvram_attr = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = RTC_OFFSET,
.read = stk17ta8_nvram_read,
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c
new file mode 100644
index 00000000000..abe87a4d266
--- /dev/null
+++ b/drivers/rtc/rtc-twl4030.c
@@ -0,0 +1,564 @@
+/*
+ * rtc-twl4030.c -- TWL4030 Real Time Clock interface
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc
+ * Author: Alexandre Rusev <source@mvista.com>
+ *
+ * Based on original TI driver twl4030-rtc.c
+ * Copyright (C) 2006 Texas Instruments, Inc.
+ *
+ * Based on rtc-omap.c
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
+ * Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * RTC block register offsets (use TWL_MODULE_RTC)
+ */
+#define REG_SECONDS_REG 0x00
+#define REG_MINUTES_REG 0x01
+#define REG_HOURS_REG 0x02
+#define REG_DAYS_REG 0x03
+#define REG_MONTHS_REG 0x04
+#define REG_YEARS_REG 0x05
+#define REG_WEEKS_REG 0x06
+
+#define REG_ALARM_SECONDS_REG 0x07
+#define REG_ALARM_MINUTES_REG 0x08
+#define REG_ALARM_HOURS_REG 0x09
+#define REG_ALARM_DAYS_REG 0x0A
+#define REG_ALARM_MONTHS_REG 0x0B
+#define REG_ALARM_YEARS_REG 0x0C
+
+#define REG_RTC_CTRL_REG 0x0D
+#define REG_RTC_STATUS_REG 0x0E
+#define REG_RTC_INTERRUPTS_REG 0x0F
+
+#define REG_RTC_COMP_LSB_REG 0x10
+#define REG_RTC_COMP_MSB_REG 0x11
+
+/* RTC_CTRL_REG bitfields */
+#define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01
+#define BIT_RTC_CTRL_REG_ROUND_30S_M 0x02
+#define BIT_RTC_CTRL_REG_AUTO_COMP_M 0x04
+#define BIT_RTC_CTRL_REG_MODE_12_24_M 0x08
+#define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10
+#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20
+#define BIT_RTC_CTRL_REG_GET_TIME_M 0x40
+
+/* RTC_STATUS_REG bitfields */
+#define BIT_RTC_STATUS_REG_RUN_M 0x02
+#define BIT_RTC_STATUS_REG_1S_EVENT_M 0x04
+#define BIT_RTC_STATUS_REG_1M_EVENT_M 0x08
+#define BIT_RTC_STATUS_REG_1H_EVENT_M 0x10
+#define BIT_RTC_STATUS_REG_1D_EVENT_M 0x20
+#define BIT_RTC_STATUS_REG_ALARM_M 0x40
+#define BIT_RTC_STATUS_REG_POWER_UP_M 0x80
+
+/* RTC_INTERRUPTS_REG bitfields */
+#define BIT_RTC_INTERRUPTS_REG_EVERY_M 0x03
+#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M 0x04
+#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M 0x08
+
+
+/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
+#define ALL_TIME_REGS 6
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Supports 1 byte read from TWL4030 RTC register.
+ */
+static int twl4030_rtc_read_u8(u8 *data, u8 reg)
+{
+ int ret;
+
+ ret = twl4030_i2c_read_u8(TWL4030_MODULE_RTC, data, reg);
+ if (ret < 0)
+ pr_err("twl4030_rtc: Could not read TWL4030"
+ "register %X - error %d\n", reg, ret);
+ return ret;
+}
+
+/*
+ * Supports 1 byte write to TWL4030 RTC registers.
+ */
+static int twl4030_rtc_write_u8(u8 data, u8 reg)
+{
+ int ret;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_RTC, data, reg);
+ if (ret < 0)
+ pr_err("twl4030_rtc: Could not write TWL4030"
+ "register %X - error %d\n", reg, ret);
+ return ret;
+}
+
+/*
+ * Cache the value for timer/alarm interrupts register; this is
+ * only changed by callers holding rtc ops lock (or resume).
+ */
+static unsigned char rtc_irq_bits;
+
+/*
+ * Enable timer and/or alarm interrupts.
+ */
+static int set_rtc_irq_bit(unsigned char bit)
+{
+ unsigned char val;
+ int ret;
+
+ val = rtc_irq_bits | bit;
+ ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+ if (ret == 0)
+ rtc_irq_bits = val;
+
+ return ret;
+}
+
+/*
+ * Disable timer and/or alarm interrupts.
+ */
+static int mask_rtc_irq_bit(unsigned char bit)
+{
+ unsigned char val;
+ int ret;
+
+ val = rtc_irq_bits & ~bit;
+ ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+ if (ret == 0)
+ rtc_irq_bits = val;
+
+ return ret;
+}
+
+static inline int twl4030_rtc_alarm_irq_set_state(int enabled)
+{
+ int ret;
+
+ if (enabled)
+ ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ else
+ ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+
+ return ret;
+}
+
+static inline int twl4030_rtc_irq_set_state(int enabled)
+{
+ int ret;
+
+ if (enabled)
+ ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+ else
+ ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+ return ret;
+}
+
+/*
+ * Gets current TWL4030 RTC time and date parameters.
+ *
+ * The RTC's time/alarm representation is not what gmtime(3) requires
+ * Linux to use:
+ *
+ * - Months are 1..12 vs Linux 0-11
+ * - Years are 0..99 vs Linux 1900..N (we assume 21st century)
+ */
+static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned char rtc_data[ALL_TIME_REGS + 1];
+ int ret;
+ u8 save_control;
+
+ ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ return ret;
+
+ save_control |= BIT_RTC_CTRL_REG_GET_TIME_M;
+
+ ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ return ret;
+
+ ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data,
+ REG_SECONDS_REG, ALL_TIME_REGS);
+
+ if (ret < 0) {
+ dev_err(dev, "rtc_read_time error %d\n", ret);
+ return ret;
+ }
+
+ tm->tm_sec = bcd2bin(rtc_data[0]);
+ tm->tm_min = bcd2bin(rtc_data[1]);
+ tm->tm_hour = bcd2bin(rtc_data[2]);
+ tm->tm_mday = bcd2bin(rtc_data[3]);
+ tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
+ tm->tm_year = bcd2bin(rtc_data[5]) + 100;
+
+ return ret;
+}
+
+static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned char save_control;
+ unsigned char rtc_data[ALL_TIME_REGS + 1];
+ int ret;
+
+ rtc_data[1] = bin2bcd(tm->tm_sec);
+ rtc_data[2] = bin2bcd(tm->tm_min);
+ rtc_data[3] = bin2bcd(tm->tm_hour);
+ rtc_data[4] = bin2bcd(tm->tm_mday);
+ rtc_data[5] = bin2bcd(tm->tm_mon + 1);
+ rtc_data[6] = bin2bcd(tm->tm_year - 100);
+
+ /* Stop RTC while updating the TC registers */
+ ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ goto out;
+
+ save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
+ twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ goto out;
+
+ /* update all the time registers in one shot */
+ ret = twl4030_i2c_write(TWL4030_MODULE_RTC, rtc_data,
+ REG_SECONDS_REG, ALL_TIME_REGS);
+ if (ret < 0) {
+ dev_err(dev, "rtc_set_time error %d\n", ret);
+ goto out;
+ }
+
+ /* Start back RTC */
+ save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
+ ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+
+out:
+ return ret;
+}
+
+/*
+ * Gets current TWL4030 RTC alarm time.
+ */
+static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ unsigned char rtc_data[ALL_TIME_REGS + 1];
+ int ret;
+
+ ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data,
+ REG_ALARM_SECONDS_REG, ALL_TIME_REGS);
+ if (ret < 0) {
+ dev_err(dev, "rtc_read_alarm error %d\n", ret);
+ return ret;
+ }
+
+ /* some of these fields may be wildcard/"match all" */
+ alm->time.tm_sec = bcd2bin(rtc_data[0]);
+ alm->time.tm_min = bcd2bin(rtc_data[1]);
+ alm->time.tm_hour = bcd2bin(rtc_data[2]);
+ alm->time.tm_mday = bcd2bin(rtc_data[3]);
+ alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
+ alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
+
+ /* report cached alarm enable state */
+ if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
+ alm->enabled = 1;
+
+ return ret;
+}
+
+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);
+ if (ret)
+ goto out;
+
+ alarm_data[1] = bin2bcd(alm->time.tm_sec);
+ alarm_data[2] = bin2bcd(alm->time.tm_min);
+ alarm_data[3] = bin2bcd(alm->time.tm_hour);
+ alarm_data[4] = bin2bcd(alm->time.tm_mday);
+ alarm_data[5] = bin2bcd(alm->time.tm_mon + 1);
+ alarm_data[6] = bin2bcd(alm->time.tm_year - 100);
+
+ /* update all the alarm registers in one shot */
+ ret = twl4030_i2c_write(TWL4030_MODULE_RTC, alarm_data,
+ REG_ALARM_SECONDS_REG, ALL_TIME_REGS);
+ if (ret) {
+ dev_err(dev, "rtc_set_alarm error %d\n", ret);
+ goto out;
+ }
+
+ if (alm->enabled)
+ ret = twl4030_rtc_alarm_irq_set_state(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 omap_rtc_ioctl NULL
+#endif
+
+static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc)
+{
+ unsigned long events = 0;
+ int ret = IRQ_NONE;
+ int res;
+ u8 rd_reg;
+
+#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
+
+ res = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+ if (res)
+ goto out;
+ /*
+ * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
+ * only one (ALARM or RTC) interrupt source may be enabled
+ * at time, we also could check our results
+ * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
+ */
+ if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
+ events |= RTC_IRQF | RTC_AF;
+ else
+ events |= RTC_IRQF | RTC_UF;
+
+ res = twl4030_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M,
+ REG_RTC_STATUS_REG);
+ if (res)
+ goto out;
+
+ /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
+ * needs 2 reads to clear the interrupt. One read is done in
+ * do_twl4030_pwrirq(). Doing the second read, to clear
+ * the bit.
+ *
+ * FIXME the reason PWR_ISR1 needs an extra read is that
+ * RTC_IF retriggered until we cleared REG_ALARM_M above.
+ * But re-reading like this is a bad hack; by doing so we
+ * risk wrongly clearing status for some other IRQ (losing
+ * the interrupt). Be smarter about handling RTC_UF ...
+ */
+ res = twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+ &rd_reg, TWL4030_INT_PWR_ISR1);
+ if (res)
+ goto out;
+
+ /* Notify RTC core on event */
+ rtc_update_irq(rtc, 1, events);
+
+ ret = IRQ_HANDLED;
+out:
+ return ret;
+}
+
+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,
+};
+
+/*----------------------------------------------------------------------*/
+
+static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ int ret = 0;
+ int irq = platform_get_irq(pdev, 0);
+ u8 rd_reg;
+
+ if (irq < 0)
+ return irq;
+
+ rtc = rtc_device_register(pdev->name,
+ &pdev->dev, &twl4030_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
+ PTR_ERR(rtc));
+ goto out0;
+
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+
+ if (ret < 0)
+ goto out1;
+
+ if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)
+ dev_warn(&pdev->dev, "Power up reset detected.\n");
+
+ if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
+ dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
+
+ /* Clear RTC Power up reset and pending alarm interrupts */
+ ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
+ if (ret < 0)
+ goto out1;
+
+ ret = request_irq(irq, twl4030_rtc_interrupt,
+ IRQF_TRIGGER_RISING,
+ rtc->dev.bus_id, rtc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "IRQ is not free.\n");
+ goto out1;
+ }
+
+ /* Check RTC module status, Enable if it is off */
+ ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ goto out2;
+
+ if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
+ dev_info(&pdev->dev, "Enabling TWL4030-RTC.\n");
+ rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
+ ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
+ if (ret < 0)
+ goto out2;
+ }
+
+ /* init cached IRQ enable bits */
+ ret = twl4030_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
+ if (ret < 0)
+ goto out2;
+
+ return ret;
+
+
+out2:
+ free_irq(irq, rtc);
+out1:
+ rtc_device_unregister(rtc);
+out0:
+ return ret;
+}
+
+/*
+ * Disable all TWL4030 RTC module interrupts.
+ * Sets status flag to free.
+ */
+static int __devexit twl4030_rtc_remove(struct platform_device *pdev)
+{
+ /* leave rtc running, but disable irqs */
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+ free_irq(irq, rtc);
+
+ rtc_device_unregister(rtc);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+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);
+}
+
+#ifdef CONFIG_PM
+
+static unsigned char irqstat;
+
+static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ irqstat = rtc_irq_bits;
+
+ /* REVISIT alarm may need to wake us from sleep */
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
+ BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ return 0;
+}
+
+static int twl4030_rtc_resume(struct platform_device *pdev)
+{
+ set_rtc_irq_bit(irqstat);
+ return 0;
+}
+
+#else
+#define twl4030_rtc_suspend NULL
+#define twl4030_rtc_resume NULL
+#endif
+
+MODULE_ALIAS("platform:twl4030_rtc");
+
+static struct platform_driver twl4030rtc_driver = {
+ .probe = twl4030_rtc_probe,
+ .remove = __devexit_p(twl4030_rtc_remove),
+ .shutdown = twl4030_rtc_shutdown,
+ .suspend = twl4030_rtc_suspend,
+ .resume = twl4030_rtc_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "twl4030_rtc",
+ },
+};
+
+static int __init twl4030_rtc_init(void)
+{
+ return platform_driver_register(&twl4030rtc_driver);
+}
+module_init(twl4030_rtc_init);
+
+static void __exit twl4030_rtc_exit(void)
+{
+ platform_driver_unregister(&twl4030rtc_driver);
+}
+module_exit(twl4030_rtc_exit);
+
+MODULE_AUTHOR("Texas Instruments, MontaVista Software");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index 10025d84026..14d4f036a76 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -92,19 +92,19 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt)
/* ...and then read constant values. */
tmp = v3020_get_reg(chip, V3020_SECONDS);
- dt->tm_sec = BCD2BIN(tmp);
+ dt->tm_sec = bcd2bin(tmp);
tmp = v3020_get_reg(chip, V3020_MINUTES);
- dt->tm_min = BCD2BIN(tmp);
+ dt->tm_min = bcd2bin(tmp);
tmp = v3020_get_reg(chip, V3020_HOURS);
- dt->tm_hour = BCD2BIN(tmp);
+ dt->tm_hour = bcd2bin(tmp);
tmp = v3020_get_reg(chip, V3020_MONTH_DAY);
- dt->tm_mday = BCD2BIN(tmp);
+ dt->tm_mday = bcd2bin(tmp);
tmp = v3020_get_reg(chip, V3020_MONTH);
- dt->tm_mon = BCD2BIN(tmp) - 1;
+ dt->tm_mon = bcd2bin(tmp) - 1;
tmp = v3020_get_reg(chip, V3020_WEEK_DAY);
- dt->tm_wday = BCD2BIN(tmp);
+ dt->tm_wday = bcd2bin(tmp);
tmp = v3020_get_reg(chip, V3020_YEAR);
- dt->tm_year = BCD2BIN(tmp)+100;
+ dt->tm_year = bcd2bin(tmp)+100;
#ifdef DEBUG
printk("\n%s : Read RTC values\n",__func__);
@@ -136,13 +136,13 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt)
#endif
/* Write all the values to ram... */
- v3020_set_reg(chip, V3020_SECONDS, BIN2BCD(dt->tm_sec));
- v3020_set_reg(chip, V3020_MINUTES, BIN2BCD(dt->tm_min));
- v3020_set_reg(chip, V3020_HOURS, BIN2BCD(dt->tm_hour));
- v3020_set_reg(chip, V3020_MONTH_DAY, BIN2BCD(dt->tm_mday));
- v3020_set_reg(chip, V3020_MONTH, BIN2BCD(dt->tm_mon + 1));
- v3020_set_reg(chip, V3020_WEEK_DAY, BIN2BCD(dt->tm_wday));
- v3020_set_reg(chip, V3020_YEAR, BIN2BCD(dt->tm_year % 100));
+ v3020_set_reg(chip, V3020_SECONDS, bin2bcd(dt->tm_sec));
+ v3020_set_reg(chip, V3020_MINUTES, bin2bcd(dt->tm_min));
+ v3020_set_reg(chip, V3020_HOURS, bin2bcd(dt->tm_hour));
+ v3020_set_reg(chip, V3020_MONTH_DAY, bin2bcd(dt->tm_mday));
+ v3020_set_reg(chip, V3020_MONTH, bin2bcd(dt->tm_mon + 1));
+ v3020_set_reg(chip, V3020_WEEK_DAY, bin2bcd(dt->tm_wday));
+ v3020_set_reg(chip, V3020_YEAR, bin2bcd(dt->tm_year % 100));
/* ...and set the clock. */
v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0);
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index 884b635f028..834dcc6d785 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -360,7 +360,7 @@ static int __devinit rtc_probe(struct platform_device *pdev)
spin_unlock_irq(&rtc_lock);
aie_irq = platform_get_irq(pdev, 0);
- if (aie_irq < 0 || aie_irq >= NR_IRQS) {
+ if (aie_irq < 0 || aie_irq >= nr_irqs) {
retval = -EBUSY;
goto err_device_unregister;
}
@@ -371,7 +371,7 @@ static int __devinit rtc_probe(struct platform_device *pdev)
goto err_device_unregister;
pie_irq = platform_get_irq(pdev, 1);
- if (pie_irq < 0 || pie_irq >= NR_IRQS)
+ if (pie_irq < 0 || pie_irq >= nr_irqs)
goto err_free_irq;
retval = request_irq(pie_irq, rtclong1_interrupt, IRQF_DISABLED,
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 7dcfba1bbfe..310c10795e9 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -118,13 +118,13 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
for (i = 0; i <= 4; i++)
buf[i] &= 0x7F;
- tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
- tm->tm_min = BCD2BIN(buf[CCR_MIN]);
- tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
- tm->tm_mday = BCD2BIN(buf[CCR_MDAY]);
- tm->tm_mon = BCD2BIN(buf[CCR_MONTH]) - 1; /* mon is 0-11 */
- tm->tm_year = BCD2BIN(buf[CCR_YEAR])
- + (BCD2BIN(buf[CCR_Y2K]) * 100) - 1900;
+ tm->tm_sec = bcd2bin(buf[CCR_SEC]);
+ tm->tm_min = bcd2bin(buf[CCR_MIN]);
+ tm->tm_hour = bcd2bin(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
+ tm->tm_mday = bcd2bin(buf[CCR_MDAY]);
+ tm->tm_mon = bcd2bin(buf[CCR_MONTH]) - 1; /* mon is 0-11 */
+ tm->tm_year = bcd2bin(buf[CCR_YEAR])
+ + (bcd2bin(buf[CCR_Y2K]) * 100) - 1900;
tm->tm_wday = buf[CCR_WDAY];
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
@@ -174,11 +174,11 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour);
- buf[CCR_SEC] = BIN2BCD(tm->tm_sec);
- buf[CCR_MIN] = BIN2BCD(tm->tm_min);
+ buf[CCR_SEC] = bin2bcd(tm->tm_sec);
+ buf[CCR_MIN] = bin2bcd(tm->tm_min);
/* set hour and 24hr bit */
- buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL;
+ buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | X1205_HR_MIL;
/* should we also set the date? */
if (datetoo) {
@@ -187,15 +187,15 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
__func__,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
- buf[CCR_MDAY] = BIN2BCD(tm->tm_mday);
+ buf[CCR_MDAY] = bin2bcd(tm->tm_mday);
/* month, 1 - 12 */
- buf[CCR_MONTH] = BIN2BCD(tm->tm_mon + 1);
+ buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1);
/* year, since the rtc epoch*/
- buf[CCR_YEAR] = BIN2BCD(tm->tm_year % 100);
+ buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100);
buf[CCR_WDAY] = tm->tm_wday & 0x07;
- buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
+ buf[CCR_Y2K] = bin2bcd(tm->tm_year / 100);
}
/* If writing alarm registers, set compare bits on registers 0-4 */
@@ -437,7 +437,7 @@ static int x1205_validate_client(struct i2c_client *client)
return -EIO;
}
- value = BCD2BIN(reg & probe_limits_pattern[i].mask);
+ value = bcd2bin(reg & probe_limits_pattern[i].mask);
if (value > probe_limits_pattern[i].max ||
value < probe_limits_pattern[i].min) {
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 0a225ccda02..4b76fca64a6 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2011,10 +2011,9 @@ static void dasd_flush_request_queue(struct dasd_block *block)
spin_unlock_irq(&block->request_queue_lock);
}
-static int dasd_open(struct inode *inp, struct file *filp)
+static int dasd_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inp->i_bdev->bd_disk;
- struct dasd_block *block = disk->private_data;
+ struct dasd_block *block = bdev->bd_disk->private_data;
struct dasd_device *base = block->base;
int rc;
@@ -2052,9 +2051,8 @@ unlock:
return rc;
}
-static int dasd_release(struct inode *inp, struct file *filp)
+static int dasd_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inp->i_bdev->bd_disk;
struct dasd_block *block = disk->private_data;
atomic_dec(&block->open_count);
@@ -2089,8 +2087,7 @@ dasd_device_operations = {
.owner = THIS_MODULE,
.open = dasd_open,
.release = dasd_release,
- .ioctl = dasd_ioctl,
- .compat_ioctl = dasd_compat_ioctl,
+ .locked_ioctl = dasd_ioctl,
.getgeo = dasd_getgeo,
};
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index aee6565aaf9..e99d566b69c 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -99,7 +99,7 @@ int dasd_scan_partitions(struct dasd_block *block)
struct block_device *bdev;
bdev = bdget_disk(block->gdp, 0);
- if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
+ if (!bdev || blkdev_get(bdev, FMODE_READ) < 0)
return -ENODEV;
/*
* See fs/partition/check.c:register_disk,rescan_partitions
@@ -152,7 +152,7 @@ void dasd_destroy_partitions(struct dasd_block *block)
invalidate_partition(block->gdp, 0);
/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
- blkdev_put(bdev);
+ blkdev_put(bdev, FMODE_READ);
set_capacity(block->gdp, 0);
}
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 489d5fe488f..05a14536c36 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -610,8 +610,7 @@ int dasd_scan_partitions(struct dasd_block *);
void dasd_destroy_partitions(struct dasd_block *);
/* externals in dasd_ioctl.c */
-int dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-long dasd_compat_ioctl(struct file *, unsigned int, unsigned long);
+int dasd_ioctl(struct block_device *, fmode_t, unsigned int, unsigned long);
/* externals in dasd_proc.c */
int dasd_proc_init(void);
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 91a64630cb0..b82d816d9ef 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -366,10 +366,9 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
}
int
-dasd_ioctl(struct inode *inode, struct file *file,
+dasd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
struct dasd_block *block = bdev->bd_disk->private_data;
void __user *argp = (void __user *)arg;
@@ -421,15 +420,3 @@ dasd_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
}
-
-long
-dasd_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- int rval;
-
- lock_kernel();
- rval = dasd_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
- unlock_kernel();
-
- return (rval == -EINVAL) ? -ENOIOCTLCMD : rval;
-}
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index a7ff167d5b8..63f26a135fe 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -31,8 +31,8 @@
#define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x)
#define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x)
-static int dcssblk_open(struct inode *inode, struct file *filp);
-static int dcssblk_release(struct inode *inode, struct file *filp);
+static int dcssblk_open(struct block_device *bdev, fmode_t mode);
+static int dcssblk_release(struct gendisk *disk, fmode_t mode);
static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
void **kaddr, unsigned long *pfn);
@@ -776,32 +776,31 @@ out_buf:
}
static int
-dcssblk_open(struct inode *inode, struct file *filp)
+dcssblk_open(struct block_device *bdev, fmode_t mode)
{
struct dcssblk_dev_info *dev_info;
int rc;
- dev_info = inode->i_bdev->bd_disk->private_data;
+ dev_info = bdev->bd_disk->private_data;
if (NULL == dev_info) {
rc = -ENODEV;
goto out;
}
atomic_inc(&dev_info->use_count);
- inode->i_bdev->bd_block_size = 4096;
+ bdev->bd_block_size = 4096;
rc = 0;
out:
return rc;
}
static int
-dcssblk_release(struct inode *inode, struct file *filp)
+dcssblk_release(struct gendisk *disk, fmode_t mode)
{
- struct dcssblk_dev_info *dev_info;
+ struct dcssblk_dev_info *dev_info = disk->private_data;
struct segment_info *entry;
int rc;
- dev_info = inode->i_bdev->bd_disk->private_data;
- if (NULL == dev_info) {
+ if (!dev_info) {
rc = -ENODEV;
goto out;
}
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index a25b8bf54f4..023803dbb0c 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -43,9 +43,9 @@
/*
* file operation structure for tape block frontend
*/
-static int tapeblock_open(struct inode *, struct file *);
-static int tapeblock_release(struct inode *, struct file *);
-static int tapeblock_ioctl(struct inode *, struct file *, unsigned int,
+static int tapeblock_open(struct block_device *, fmode_t);
+static int tapeblock_release(struct gendisk *, fmode_t);
+static int tapeblock_ioctl(struct block_device *, fmode_t, unsigned int,
unsigned long);
static int tapeblock_medium_changed(struct gendisk *);
static int tapeblock_revalidate_disk(struct gendisk *);
@@ -54,7 +54,7 @@ static struct block_device_operations tapeblock_fops = {
.owner = THIS_MODULE,
.open = tapeblock_open,
.release = tapeblock_release,
- .ioctl = tapeblock_ioctl,
+ .locked_ioctl = tapeblock_ioctl,
.media_changed = tapeblock_medium_changed,
.revalidate_disk = tapeblock_revalidate_disk,
};
@@ -364,13 +364,12 @@ tapeblock_medium_changed(struct gendisk *disk)
* Block frontend tape device open function.
*/
static int
-tapeblock_open(struct inode *inode, struct file *filp)
+tapeblock_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk * disk;
+ struct gendisk * disk = bdev->bd_disk;
struct tape_device * device;
int rc;
- disk = inode->i_bdev->bd_disk;
device = tape_get_device_reference(disk->private_data);
if (device->required_tapemarks) {
@@ -410,9 +409,8 @@ release:
* we just get the pointer here and release the reference.
*/
static int
-tapeblock_release(struct inode *inode, struct file *filp)
+tapeblock_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
struct tape_device *device = disk->private_data;
tape_state_set(device, TS_IN_USE);
@@ -427,22 +425,21 @@ tapeblock_release(struct inode *inode, struct file *filp)
*/
static int
tapeblock_ioctl(
- struct inode * inode,
- struct file * file,
+ struct block_device * bdev,
+ fmode_t mode,
unsigned int command,
unsigned long arg
) {
int rc;
int minor;
- struct gendisk *disk;
+ struct gendisk *disk = bdev->bd_disk;
struct tape_device *device;
rc = 0;
- disk = inode->i_bdev->bd_disk;
BUG_ON(!disk);
device = disk->private_data;
BUG_ON(!device);
- minor = iminor(inode);
+ minor = MINOR(bdev->bd_dev);
DBF_LH(6, "tapeblock_ioctl(0x%0x)\n", command);
DBF_LH(6, "device = %d:%d\n", tapeblock_major, minor);
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 326db1e827c..e3fe6838293 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -659,9 +659,9 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf,
hr_time = ktime_set(0, poll_timeout);
if (!hrtimer_is_queued(&ap_poll_timer) ||
- !hrtimer_forward(&ap_poll_timer, ap_poll_timer.expires, hr_time)) {
- ap_poll_timer.expires = hr_time;
- hrtimer_start(&ap_poll_timer, hr_time, HRTIMER_MODE_ABS);
+ !hrtimer_forward(&ap_poll_timer, hrtimer_get_expires(&ap_poll_timer), hr_time)) {
+ hrtimer_set_expires(&ap_poll_timer, hr_time);
+ hrtimer_start_expires(&ap_poll_timer, HRTIMER_MODE_ABS);
}
return count;
}
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index b5a868d85eb..1e5478abd90 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -337,7 +337,7 @@ CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
#else
#define IRQ_MIN 9
#if defined(__PPC)
-#define IRQ_MAX (NR_IRQS-1)
+#define IRQ_MAX (nr_irqs-1)
#else
#define IRQ_MAX 12
#endif
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index 69f8346aa28..5877f29a600 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -189,7 +189,6 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = {
.attr = {
.name = "mu_read",
.mode = S_IRUSR ,
- .owner = THIS_MODULE,
},
.size = 1032,
.read = arcmsr_sysfs_iop_message_read,
@@ -199,7 +198,6 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = {
.attr = {
.name = "mu_write",
.mode = S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 1032,
.write = arcmsr_sysfs_iop_message_write,
@@ -209,7 +207,6 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
.attr = {
.name = "mu_clear",
.mode = S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 1,
.write = arcmsr_sysfs_iop_message_clear,
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 740bad43599..2370fd82ebf 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -343,6 +343,11 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *r
}
#ifdef CONFIG_IDE_PROC_FS
+static ide_proc_entry_t idescsi_proc[] = {
+ { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
+ { NULL, 0, NULL, NULL }
+};
+
#define ide_scsi_devset_get(name, field) \
static int get_##name(ide_drive_t *drive) \
{ \
@@ -378,6 +383,16 @@ static const struct ide_proc_devset idescsi_settings[] = {
IDE_PROC_DEVSET(transform, 0, 3),
{ 0 },
};
+
+static ide_proc_entry_t *ide_scsi_proc_entries(ide_drive_t *drive)
+{
+ return idescsi_proc;
+}
+
+static const struct ide_proc_devset *ide_scsi_proc_devsets(ide_drive_t *drive)
+{
+ return idescsi_settings;
+}
#endif
/*
@@ -419,13 +434,6 @@ static void ide_scsi_remove(ide_drive_t *drive)
static int ide_scsi_probe(ide_drive_t *);
-#ifdef CONFIG_IDE_PROC_FS
-static ide_proc_entry_t idescsi_proc[] = {
- { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
- { NULL, 0, NULL, NULL }
-};
-#endif
-
static ide_driver_t idescsi_driver = {
.gen_driver = {
.owner = THIS_MODULE,
@@ -439,45 +447,39 @@ static ide_driver_t idescsi_driver = {
.end_request = idescsi_end_request,
.error = idescsi_atapi_error,
#ifdef CONFIG_IDE_PROC_FS
- .proc = idescsi_proc,
- .settings = idescsi_settings,
+ .proc_entries = ide_scsi_proc_entries,
+ .proc_devsets = ide_scsi_proc_devsets,
#endif
};
-static int idescsi_ide_open(struct inode *inode, struct file *filp)
+static int idescsi_ide_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct ide_scsi_obj *scsi;
+ struct ide_scsi_obj *scsi = ide_scsi_get(bdev->bd_disk);
- if (!(scsi = ide_scsi_get(disk)))
+ if (!scsi)
return -ENXIO;
return 0;
}
-static int idescsi_ide_release(struct inode *inode, struct file *filp)
+static int idescsi_ide_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct ide_scsi_obj *scsi = ide_scsi_g(disk);
-
- ide_scsi_put(scsi);
-
+ ide_scsi_put(ide_scsi_g(disk));
return 0;
}
-static int idescsi_ide_ioctl(struct inode *inode, struct file *file,
+static int idescsi_ide_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
struct ide_scsi_obj *scsi = ide_scsi_g(bdev->bd_disk);
- return generic_ide_ioctl(scsi->drive, file, bdev, cmd, arg);
+ return generic_ide_ioctl(scsi->drive, bdev, cmd, arg);
}
static struct block_device_operations idescsi_ops = {
.owner = THIS_MODULE,
.open = idescsi_ide_open,
.release = idescsi_ide_release,
- .ioctl = idescsi_ide_ioctl,
+ .locked_ioctl = idescsi_ide_ioctl,
};
static int idescsi_slave_configure(struct scsi_device * sdp)
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index de62f4dfeb0..ded854a6dd3 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -7853,7 +7853,6 @@ static struct pci_driver ipr_driver = {
.remove = ipr_remove,
.shutdown = ipr_shutdown,
.err_handler = &ipr_err_handler,
- .dynids.use_driver_data = 1
};
/**
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 83c81921677..f25f41a499e 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2108,7 +2108,7 @@ struct scsi_qla_host;
struct qla_msix_entry {
int have_irq;
- uint16_t msix_vector;
+ uint32_t msix_vector;
uint16_t msix_entry;
};
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 2aed4721c0d..21dd182ad51 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1566,9 +1566,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto probe_out;
}
- if (pci_find_aer_capability(pdev))
- if (pci_enable_pcie_error_reporting(pdev))
- goto probe_out;
+ /* This may fail but that's ok */
+ pci_enable_pcie_error_reporting(pdev);
host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
if (host == NULL) {
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 28b19ef2630..dc1cfb2fd76 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -237,7 +237,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
case SCSI_IOCTL_SEND_COMMAND:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES;
- return sg_scsi_ioctl(NULL, sdev->request_queue, NULL, arg);
+ return sg_scsi_ioctl(sdev->request_queue, NULL, 0, arg);
case SCSI_IOCTL_DOORLOCK:
return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
case SCSI_IOCTL_DOORUNLOCK:
@@ -277,14 +277,14 @@ EXPORT_SYMBOL(scsi_ioctl);
* @filp: either NULL or a &struct file which must have the O_NONBLOCK flag.
*/
int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
- void __user *arg, struct file *filp)
+ void __user *arg, int ndelay)
{
int val, result;
/* The first set of iocts may be executed even if we're doing
* error processing, as long as the device was opened
* non-blocking */
- if (filp && (filp->f_flags & O_NONBLOCK)) {
+ if (ndelay) {
if (scsi_host_in_recovery(sdev->host))
return -ENODEV;
} else if (!scsi_block_when_processing_errors(sdev))
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 7ba70bef8b5..c9e1242eaf2 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -609,17 +609,15 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
* In the latter case @inode and @filp carry an abridged amount
* of information as noted above.
**/
-static int sd_open(struct inode *inode, struct file *filp)
+static int sd_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct scsi_disk *sdkp;
+ struct scsi_disk *sdkp = scsi_disk_get(bdev->bd_disk);
struct scsi_device *sdev;
int retval;
- if (!(sdkp = scsi_disk_get(disk)))
+ if (!sdkp)
return -ENXIO;
-
SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n"));
sdev = sdkp->device;
@@ -633,14 +631,13 @@ static int sd_open(struct inode *inode, struct file *filp)
goto error_out;
if (sdev->removable || sdkp->write_prot)
- check_disk_change(inode->i_bdev);
+ check_disk_change(bdev);
/*
* If the drive is empty, just let the open fail.
*/
retval = -ENOMEDIUM;
- if (sdev->removable && !sdkp->media_present &&
- !(filp->f_flags & O_NDELAY))
+ if (sdev->removable && !sdkp->media_present && !(mode & FMODE_NDELAY))
goto error_out;
/*
@@ -648,7 +645,7 @@ static int sd_open(struct inode *inode, struct file *filp)
* if the user expects to be able to write to the thing.
*/
retval = -EROFS;
- if (sdkp->write_prot && (filp->f_mode & FMODE_WRITE))
+ if (sdkp->write_prot && (mode & FMODE_WRITE))
goto error_out;
/*
@@ -684,9 +681,8 @@ error_out:
* Note: may block (uninterruptible) if error recovery is underway
* on this disk.
**/
-static int sd_release(struct inode *inode, struct file *filp)
+static int sd_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdev = sdkp->device;
@@ -743,10 +739,9 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
* Note: most ioctls are forward onto the block subsystem or further
* down in the scsi subsystem.
**/
-static int sd_ioctl(struct inode * inode, struct file * filp,
+static int sd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
struct scsi_device *sdp = scsi_disk(disk)->device;
void __user *p = (void __user *)arg;
@@ -761,7 +756,8 @@ static int sd_ioctl(struct inode * inode, struct file * filp,
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
- error = scsi_nonblockable_ioctl(sdp, cmd, p, filp);
+ error = scsi_nonblockable_ioctl(sdp, cmd, p,
+ (mode & FMODE_NDELAY_NOW) != 0);
if (!scsi_block_when_processing_errors(sdp) || !error)
return error;
@@ -775,7 +771,7 @@ static int sd_ioctl(struct inode * inode, struct file * filp,
case SCSI_IOCTL_GET_BUS_NUMBER:
return scsi_ioctl(sdp, cmd, p);
default:
- error = scsi_cmd_ioctl(filp, disk->queue, disk, cmd, p);
+ error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p);
if (error != -ENOTTY)
return error;
}
@@ -928,11 +924,10 @@ static void sd_rescan(struct device *dev)
* This gets directly called from VFS. When the ioctl
* is not recognized we go back to the other translation paths.
*/
-static long sd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev;
- struct gendisk *disk = bdev->bd_disk;
- struct scsi_device *sdev = scsi_disk(disk)->device;
+ struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device;
/*
* If we are in the middle of error recovery, don't let anyone
@@ -962,7 +957,7 @@ static struct block_device_operations sd_fops = {
.owner = THIS_MODULE,
.open = sd_open,
.release = sd_release,
- .ioctl = sd_ioctl,
+ .locked_ioctl = sd_ioctl,
.getgeo = sd_getgeo,
#ifdef CONFIG_COMPAT
.compat_ioctl = sd_compat_ioctl,
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 93bd59a1ed7..9adf35bd8b5 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1059,7 +1059,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
if (sg_allow_access(filp, &opcode))
return -EPERM;
}
- return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p);
+ return sg_scsi_ioctl(sdp->device->request_queue, NULL, filp->f_mode, p);
case SG_SET_DEBUG:
result = get_user(val, ip);
if (result)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 0f17009c99d..62b6633e3a9 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -471,38 +471,31 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq)
return scsi_prep_return(q, rq, ret);
}
-static int sr_block_open(struct inode *inode, struct file *file)
+static int sr_block_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct scsi_cd *cd;
- int ret = 0;
-
- if(!(cd = scsi_cd_get(disk)))
- return -ENXIO;
-
- if((ret = cdrom_open(&cd->cdi, inode, file)) != 0)
- scsi_cd_put(cd);
+ struct scsi_cd *cd = scsi_cd_get(bdev->bd_disk);
+ int ret = -ENXIO;
+ if (cd) {
+ ret = cdrom_open(&cd->cdi, bdev, mode);
+ if (ret)
+ scsi_cd_put(cd);
+ }
return ret;
}
-static int sr_block_release(struct inode *inode, struct file *file)
+static int sr_block_release(struct gendisk *disk, fmode_t mode)
{
- int ret;
- struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
- ret = cdrom_release(&cd->cdi, file);
- if(ret)
- return ret;
-
+ struct scsi_cd *cd = scsi_cd(disk);
+ cdrom_release(&cd->cdi, mode);
scsi_cd_put(cd);
-
return 0;
}
-static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
+static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
unsigned long arg)
{
- struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
+ struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
struct scsi_device *sdev = cd->device;
void __user *argp = (void __user *)arg;
int ret;
@@ -517,7 +510,7 @@ static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
return scsi_ioctl(sdev, cmd, argp);
}
- ret = cdrom_ioctl(file, &cd->cdi, inode, cmd, arg);
+ ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg);
if (ret != -ENOSYS)
return ret;
@@ -527,7 +520,8 @@ static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
* case fall through to scsi_ioctl, which will return ENDOEV again
* if it doesn't recognise the ioctl
*/
- ret = scsi_nonblockable_ioctl(sdev, cmd, argp, NULL);
+ ret = scsi_nonblockable_ioctl(sdev, cmd, argp,
+ (mode & FMODE_NDELAY_NOW) != 0);
if (ret != -ENODEV)
return ret;
return scsi_ioctl(sdev, cmd, argp);
@@ -544,7 +538,7 @@ static struct block_device_operations sr_bdops =
.owner = THIS_MODULE,
.open = sr_block_open,
.release = sr_block_release,
- .ioctl = sr_block_ioctl,
+ .locked_ioctl = sr_block_ioctl,
.media_changed = sr_block_media_changed,
/*
* No compat_ioctl for now because sr_block_ioctl never
diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c
index 4eb3da996b3..4ad3e017213 100644
--- a/drivers/scsi/sr_vendor.c
+++ b/drivers/scsi/sr_vendor.c
@@ -223,9 +223,9 @@ int sr_cd_check(struct cdrom_device_info *cdi)
no_multi = 1;
break;
}
- min = BCD2BIN(buffer[15]);
- sec = BCD2BIN(buffer[16]);
- frame = BCD2BIN(buffer[17]);
+ min = bcd2bin(buffer[15]);
+ sec = bcd2bin(buffer[16]);
+ frame = bcd2bin(buffer[17]);
sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
break;
}
@@ -252,9 +252,9 @@ int sr_cd_check(struct cdrom_device_info *cdi)
}
if (rc != 0)
break;
- min = BCD2BIN(buffer[1]);
- sec = BCD2BIN(buffer[2]);
- frame = BCD2BIN(buffer[3]);
+ min = bcd2bin(buffer[1]);
+ sec = bcd2bin(buffer[2]);
+ frame = bcd2bin(buffer[3]);
sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
if (sector)
sector -= CD_MSF_OFFSET;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 5c28d08f18f..c959bdc55f4 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3263,7 +3263,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
- retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p, file);
+ retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p,
+ file->f_flags & O_NDELAY);
if (!scsi_block_when_processing_errors(STp->device) || retval != -ENODEV)
goto out;
retval = 0;
@@ -3567,8 +3568,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
!capable(CAP_SYS_RAWIO))
i = -EPERM;
else
- i = scsi_cmd_ioctl(file, STp->disk->queue,
- STp->disk, cmd_in, p);
+ i = scsi_cmd_ioctl(STp->disk->queue, STp->disk,
+ file->f_mode, cmd_in, p);
if (i != -ENOTTY)
return i;
break;
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 381b12ac20e..d935b2d04f9 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -66,7 +66,6 @@
#endif
static struct m68k_serial m68k_soft[NR_PORTS];
-struct m68k_serial *IRQ_ports[NR_IRQS];
static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
@@ -375,15 +374,11 @@ clear_and_return:
*/
irqreturn_t rs_interrupt(int irq, void *dev_id)
{
- struct m68k_serial * info;
+ struct m68k_serial *info = dev_id;
m68328_uart *uart;
unsigned short rx;
unsigned short tx;
- info = IRQ_ports[irq];
- if(!info)
- return IRQ_NONE;
-
uart = &uart_addr[info->line];
rx = uart->urx.w;
@@ -1383,8 +1378,6 @@ rs68328_init(void)
info->port, info->irq);
printk(" is a builtin MC68328 UART\n");
- IRQ_ports[info->irq] = info; /* waste of space */
-
#ifdef CONFIG_M68VZ328
if (i > 0 )
PJSEL &= 0xCF; /* PSW enable second port output */
@@ -1393,7 +1386,7 @@ rs68328_init(void)
if (request_irq(uart_irqs[i],
rs_interrupt,
IRQF_DISABLED,
- "M68328_UART", NULL))
+ "M68328_UART", info))
panic("Unable to attach 68328 serial interrupt\n");
}
local_irq_restore(flags);
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 1528de23a65..303272af386 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -156,11 +156,15 @@ struct uart_8250_port {
};
struct irq_info {
- spinlock_t lock;
+ struct hlist_node node;
+ int irq;
+ spinlock_t lock; /* Protects list not the hash */
struct list_head *head;
};
-static struct irq_info irq_lists[NR_IRQS];
+#define NR_IRQ_HASH 32 /* Can be adjusted later */
+static struct hlist_head irq_lists[NR_IRQ_HASH];
+static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */
/*
* Here we define the default xmit fifo size used for each type of UART.
@@ -1545,15 +1549,43 @@ static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
BUG_ON(i->head != &up->list);
i->head = NULL;
}
-
spin_unlock_irq(&i->lock);
+ /* List empty so throw away the hash node */
+ if (i->head == NULL) {
+ hlist_del(&i->node);
+ kfree(i);
+ }
}
static int serial_link_irq_chain(struct uart_8250_port *up)
{
- struct irq_info *i = irq_lists + up->port.irq;
+ struct hlist_head *h;
+ struct hlist_node *n;
+ struct irq_info *i;
int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
+ mutex_lock(&hash_mutex);
+
+ h = &irq_lists[up->port.irq % NR_IRQ_HASH];
+
+ hlist_for_each(n, h) {
+ i = hlist_entry(n, struct irq_info, node);
+ if (i->irq == up->port.irq)
+ break;
+ }
+
+ if (n == NULL) {
+ i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
+ if (i == NULL) {
+ mutex_unlock(&hash_mutex);
+ return -ENOMEM;
+ }
+ spin_lock_init(&i->lock);
+ i->irq = up->port.irq;
+ hlist_add_head(&i->node, h);
+ }
+ mutex_unlock(&hash_mutex);
+
spin_lock_irq(&i->lock);
if (i->head) {
@@ -1577,14 +1609,28 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
static void serial_unlink_irq_chain(struct uart_8250_port *up)
{
- struct irq_info *i = irq_lists + up->port.irq;
+ struct irq_info *i;
+ struct hlist_node *n;
+ struct hlist_head *h;
+ mutex_lock(&hash_mutex);
+
+ h = &irq_lists[up->port.irq % NR_IRQ_HASH];
+
+ hlist_for_each(n, h) {
+ i = hlist_entry(n, struct irq_info, node);
+ if (i->irq == up->port.irq)
+ break;
+ }
+
+ BUG_ON(n == NULL);
BUG_ON(i->head == NULL);
if (list_empty(i->head))
free_irq(up->port.irq, i);
serial_do_unlink(i, up);
+ mutex_unlock(&hash_mutex);
}
/* Base timer interval for polling */
@@ -2447,7 +2493,7 @@ static void serial8250_config_port(struct uart_port *port, int flags)
static int
serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
{
- if (ser->irq >= NR_IRQS || ser->irq < 0 ||
+ if (ser->irq >= nr_irqs || ser->irq < 0 ||
ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
ser->type == PORT_STARTECH)
@@ -2967,7 +3013,7 @@ EXPORT_SYMBOL(serial8250_unregister_port);
static int __init serial8250_init(void)
{
- int ret, i;
+ int ret;
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
@@ -2976,9 +3022,6 @@ static int __init serial8250_init(void)
"%d ports, IRQ sharing %sabled\n", nr_uarts,
share_irqs ? "en" : "dis");
- for (i = 0; i < NR_IRQS; i++)
- spin_lock_init(&irq_lists[i].lock);
-
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
#else
@@ -3006,15 +3049,15 @@ static int __init serial8250_init(void)
goto out;
platform_device_del(serial8250_isa_devs);
- put_dev:
+put_dev:
platform_device_put(serial8250_isa_devs);
- unreg_uart_drv:
+unreg_uart_drv:
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
#else
uart_unregister_driver(&serial8250_reg);
#endif
- out:
+out:
return ret;
}
diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c
index 0416ad3bc12..418b4fe9a0a 100644
--- a/drivers/serial/8250_gsc.c
+++ b/drivers/serial/8250_gsc.c
@@ -111,7 +111,7 @@ static struct parisc_driver serial_driver = {
.probe = serial_init_chip,
};
-int __init probe_serial_gsc(void)
+static int __init probe_serial_gsc(void)
{
register_parisc_driver(&lasi_driver);
register_parisc_driver(&serial_driver);
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index c014ffb110e..5450a0e5ecd 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -1100,6 +1100,8 @@ enum pci_board_num_t {
pbn_b0_4_1843200_200,
pbn_b0_8_1843200_200,
+ pbn_b0_1_4000000,
+
pbn_b0_bt_1_115200,
pbn_b0_bt_2_115200,
pbn_b0_bt_8_115200,
@@ -1167,6 +1169,10 @@ enum pci_board_num_t {
pbn_exsys_4055,
pbn_plx_romulus,
pbn_oxsemi,
+ pbn_oxsemi_1_4000000,
+ pbn_oxsemi_2_4000000,
+ pbn_oxsemi_4_4000000,
+ pbn_oxsemi_8_4000000,
pbn_intel_i960,
pbn_sgi_ioc3,
pbn_computone_4,
@@ -1290,6 +1296,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 1843200,
.uart_offset = 0x200,
},
+ [pbn_b0_1_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 4000000,
+ .uart_offset = 8,
+ },
[pbn_b0_bt_1_115200] = {
.flags = FL_BASE0|FL_BASE_BARS,
@@ -1625,6 +1637,35 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 115200,
.uart_offset = 8,
},
+ [pbn_oxsemi_1_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_oxsemi_2_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_oxsemi_4_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_oxsemi_8_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+
/*
* EKF addition for i960 Boards form EKF with serial port.
@@ -1813,6 +1854,39 @@ serial_pci_matches(struct pciserial_board *board,
board->first_offset == guessed->first_offset;
}
+/*
+ * Oxford Semiconductor Inc.
+ * Check that device is part of the Tornado range of devices, then determine
+ * the number of ports available on the device.
+ */
+static int pci_oxsemi_tornado_init(struct pci_dev *dev, struct pciserial_board *board)
+{
+ u8 __iomem *p;
+ unsigned long deviceID;
+ unsigned int number_uarts;
+
+ /* OxSemi Tornado devices are all 0xCxxx */
+ if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
+ (dev->device & 0xF000) != 0xC000)
+ return 0;
+
+ p = pci_iomap(dev, 0, 5);
+ if (p == NULL)
+ return -ENOMEM;
+
+ deviceID = ioread32(p);
+ /* Tornado device */
+ if (deviceID == 0x07000200) {
+ number_uarts = ioread8(p + 4);
+ board->num_ports = number_uarts;
+ printk(KERN_DEBUG
+ "%d ports detected on Oxford PCI Express device\n",
+ number_uarts);
+ }
+ pci_iounmap(dev, p);
+ return 0;
+}
+
struct serial_private *
pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
{
@@ -1821,6 +1895,13 @@ pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
struct pci_serial_quirk *quirk;
int rc, nr_ports, i;
+ /*
+ * Find number of ports on board
+ */
+ if (dev->vendor == PCI_VENDOR_ID_OXSEMI ||
+ dev->vendor == PCI_VENDOR_ID_MAINPINE)
+ pci_oxsemi_tornado_init(dev, board);
+
nr_ports = board->num_ports;
/*
@@ -2301,6 +2382,156 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_b0_bt_2_921600 },
/*
+ * Oxford Semiconductor Inc. Tornado PCI express device range.
+ */
+ { PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ /*
+ * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
+ */
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ /*
* SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
* from skokodyn@yahoo.com
*/
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index db783b77a88..c94d3c4b752 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -457,7 +457,7 @@ config SERIAL_SAMSUNG
config SERIAL_SAMSUNG_DEBUG
bool "Samsung SoC serial debug"
- depends on SERIAL_SAMSUNG
+ depends on SERIAL_SAMSUNG && DEBUG_LL
help
Add support for debugging the serial driver. Since this is
generally being used as a console, we use our own output
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 90b56c2c31e..71562689116 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -512,7 +512,7 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
ret = -EINVAL;
- if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ if (ser->irq < 0 || ser->irq >= nr_irqs)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 9d08f27208a..b7180046f8d 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -572,7 +572,7 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
ret = -EINVAL;
- if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ if (ser->irq < 0 || ser->irq >= nr_irqs)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index a6c4d744495..bde4b4b0b80 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -623,7 +623,7 @@ static int cpm_uart_verify_port(struct uart_port *port,
if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
ret = -EINVAL;
- if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ if (ser->irq < 0 || ser->irq >= nr_irqs)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index 23d03051101..611c97a1565 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -922,7 +922,7 @@ static void m32r_sio_config_port(struct uart_port *port, int flags)
static int
m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser)
{
- if (ser->irq >= NR_IRQS || ser->irq < 0 ||
+ if (ser->irq >= nr_irqs || ser->irq < 0 ||
ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
ser->type >= ARRAY_SIZE(uart_config))
return -EINVAL;
@@ -1162,7 +1162,7 @@ static int __init m32r_sio_init(void)
printk(KERN_INFO "Serial: M32R SIO driver\n");
- for (i = 0; i < NR_IRQS; i++)
+ for (i = 0; i < nr_irqs; i++)
spin_lock_init(&irq_lists[i].lock);
ret = uart_register_driver(&m32r_sio_reg);
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 6bdf3362e3b..874786a11fe 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -741,7 +741,7 @@ static int uart_set_info(struct uart_state *state,
if (port->ops->verify_port)
retval = port->ops->verify_port(port, &new_serial);
- if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
+ if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) ||
(new_serial.baud_base < 9600))
retval = -EINVAL;
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
index cb49a5ac022..61dc8b3daa2 100644
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/serial/serial_lh7a40x.c
@@ -460,7 +460,7 @@ static int lh7a40xuart_verify_port (struct uart_port* port,
if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
ret = -EINVAL;
- if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ if (ser->irq < 0 || ser->irq >= nr_irqs)
ret = -EINVAL;
if (ser->baud_base < 9600) /* *** FIXME: is this true? */
ret = -EINVAL;
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 8fcb4c5b9a2..7313c2edcb8 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -1039,7 +1039,7 @@ static int __devinit serial_txx9_probe(struct platform_device *dev)
ret = serial_txx9_register_port(&port);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
- "(IO%x MEM%llx IRQ%d): %d\n", i,
+ "(IO%lx MEM%llx IRQ%d): %d\n", i,
p->iobase, (unsigned long long)p->mapbase,
p->irq, ret);
}
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 3df2aaec829..f0658d2c45b 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -3,7 +3,7 @@
*
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
*
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 2008 Paul Mundt
* Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
*
* based off of the old drivers/char/sh-sci.c by:
@@ -46,6 +46,7 @@
#include <linux/cpufreq.h>
#include <linux/clk.h>
#include <linux/ctype.h>
+#include <linux/err.h>
#ifdef CONFIG_SUPERH
#include <asm/clock.h>
@@ -78,7 +79,7 @@ struct sci_port {
struct timer_list break_timer;
int break_flag;
-#ifdef CONFIG_SUPERH
+#ifdef CONFIG_HAVE_CLK
/* Port clock */
struct clk *clk;
#endif
@@ -831,7 +832,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
return IRQ_HANDLED;
}
-#ifdef CONFIG_CPU_FREQ
+#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_HAVE_CLK)
/*
* Here we define a transistion notifier so that we can update all of our
* ports' baud rate when the peripheral clock changes.
@@ -860,7 +861,7 @@ static int sci_notifier(struct notifier_block *self,
* Clean this up later..
*/
clk = clk_get(NULL, "module_clk");
- port->uartclk = clk_get_rate(clk) * 16;
+ port->uartclk = clk_get_rate(clk);
clk_put(clk);
}
@@ -873,7 +874,7 @@ static int sci_notifier(struct notifier_block *self,
}
static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 };
-#endif /* CONFIG_CPU_FREQ */
+#endif /* CONFIG_CPU_FREQ && CONFIG_HAVE_CLK */
static int sci_request_irq(struct sci_port *port)
{
@@ -1008,7 +1009,7 @@ static int sci_startup(struct uart_port *port)
if (s->enable)
s->enable(port);
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+#ifdef CONFIG_HAVE_CLK
s->clk = clk_get(NULL, "module_clk");
#endif
@@ -1030,7 +1031,7 @@ static void sci_shutdown(struct uart_port *port)
if (s->disable)
s->disable(port);
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+#ifdef CONFIG_HAVE_CLK
clk_put(s->clk);
s->clk = NULL;
#endif
@@ -1041,24 +1042,11 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct sci_port *s = &sci_ports[port->line];
unsigned int status, baud, smr_val;
- int t;
+ int t = -1;
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-
- switch (baud) {
- case 0:
- t = -1;
- break;
- default:
- {
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
- t = SCBRR_VALUE(baud, clk_get_rate(s->clk));
-#else
- t = SCBRR_VALUE(baud);
-#endif
- break;
- }
- }
+ if (likely(baud))
+ t = SCBRR_VALUE(baud, port->uartclk);
do {
status = sci_in(port, SCxSR);
@@ -1113,7 +1101,7 @@ static const char *sci_type(struct uart_port *port)
case PORT_IRDA: return "irda";
}
- return 0;
+ return NULL;
}
static void sci_release_port(struct uart_port *port)
@@ -1145,19 +1133,23 @@ static void sci_config_port(struct uart_port *port, int flags)
break;
}
-#if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
- if (port->mapbase == 0)
+ if (port->flags & UPF_IOREMAP && !port->membase) {
+#if defined(CONFIG_SUPERH64)
port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF");
-
- port->membase = (void __iomem *)port->mapbase;
+ port->membase = (void __iomem *)port->mapbase;
+#else
+ port->membase = ioremap_nocache(port->mapbase, 0x40);
#endif
+
+ printk(KERN_ERR "sci: can't remap port#%d\n", port->line);
+ }
}
static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
{
struct sci_port *s = &sci_ports[port->line];
- if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > NR_IRQS)
+ if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
return -EINVAL;
if (ser->baud_base < 2400)
/* No paper tape reader for Mitch.. */
@@ -1207,17 +1199,17 @@ static void __init sci_init_ports(void)
sci_ports[i].disable = h8300_sci_disable;
#endif
sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK;
-#elif defined(CONFIG_SUPERH64)
- sci_ports[i].port.uartclk = current_cpu_data.module_clock * 16;
-#else
+#elif defined(CONFIG_HAVE_CLK)
/*
* XXX: We should use a proper SCI/SCIF clock
*/
{
struct clk *clk = clk_get(NULL, "module_clk");
- sci_ports[i].port.uartclk = clk_get_rate(clk) * 16;
+ sci_ports[i].port.uartclk = clk_get_rate(clk);
clk_put(clk);
}
+#else
+#error "Need a valid uartclk"
#endif
sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i];
@@ -1285,7 +1277,7 @@ static int __init serial_console_setup(struct console *co, char *options)
port->type = serial_console_port->type;
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+#ifdef CONFIG_HAVE_CLK
if (!serial_console_port->clk)
serial_console_port->clk = clk_get(NULL, "module_clk");
#endif
@@ -1436,7 +1428,7 @@ static struct uart_driver sci_uart_driver = {
static int __devinit sci_probe(struct platform_device *dev)
{
struct plat_sci_port *p = dev->dev.platform_data;
- int i;
+ int i, ret = -EINVAL;
for (i = 0; p && p->flags != 0; p++, i++) {
struct sci_port *sciport = &sci_ports[i];
@@ -1453,12 +1445,22 @@ static int __devinit sci_probe(struct platform_device *dev)
sciport->port.mapbase = p->mapbase;
- /*
- * For the simple (and majority of) cases where we don't need
- * to do any remapping, just cast the cookie directly.
- */
- if (p->mapbase && !p->membase && !(p->flags & UPF_IOREMAP))
- p->membase = (void __iomem *)p->mapbase;
+ if (p->mapbase && !p->membase) {
+ if (p->flags & UPF_IOREMAP) {
+ p->membase = ioremap_nocache(p->mapbase, 0x40);
+ if (IS_ERR(p->membase)) {
+ ret = PTR_ERR(p->membase);
+ goto err_unreg;
+ }
+ } else {
+ /*
+ * For the simple (and majority of) cases
+ * where we don't need to do any remapping,
+ * just cast the cookie directly.
+ */
+ p->membase = (void __iomem *)p->mapbase;
+ }
+ }
sciport->port.membase = p->membase;
@@ -1479,7 +1481,7 @@ static int __devinit sci_probe(struct platform_device *dev)
kgdb_putchar = kgdb_sci_putchar;
#endif
-#ifdef CONFIG_CPU_FREQ
+#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_HAVE_CLK)
cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
dev_info(&dev->dev, "CPU frequency notifier registered\n");
#endif
@@ -1489,6 +1491,12 @@ static int __devinit sci_probe(struct platform_device *dev)
#endif
return 0;
+
+err_unreg:
+ for (i = i - 1; i >= 0; i--)
+ uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port);
+
+ return ret;
}
static int __devexit sci_remove(struct platform_device *dev)
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 8a0749e34ca..7cd28b22680 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -320,18 +320,16 @@
#define SCI_EVENT_WRITE_WAKEUP 0
#define SCI_IN(size, offset) \
- unsigned int addr = port->mapbase + (offset); \
if ((size) == 8) { \
- return ctrl_inb(addr); \
+ return ioread8(port->membase + (offset)); \
} else { \
- return ctrl_inw(addr); \
+ return ioread16(port->membase + (offset)); \
}
#define SCI_OUT(size, offset, value) \
- unsigned int addr = port->mapbase + (offset); \
if ((size) == 8) { \
- ctrl_outb(value, addr); \
+ iowrite8(value, port->membase + (offset)); \
} else if ((size) == 16) { \
- ctrl_outw(value, addr); \
+ iowrite16(value, port->membase + (offset)); \
}
#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
@@ -791,11 +789,16 @@ static inline int sci_rxd_in(struct uart_port *port)
defined(CONFIG_CPU_SUBTYPE_SH7721)
#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(16*bps)-1)
+static inline int scbrr_calc(struct uart_port *port, int bps, int clk)
+{
+ if (port->type == PORT_SCIF)
+ return (clk+16*bps)/(32*bps)-1;
+ else
+ return ((clk*2)+16*bps)/(16*bps)-1;
+}
+#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk)
#elif defined(__H8300H__) || defined(__H8300S__)
-#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
-#elif defined(CONFIG_SUPERH64)
-#define SCBRR_VALUE(bps) ((current_cpu_data.module_clock+16*bps)/(32*bps)-1)
+#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1)
#else /* Generic SH */
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1)
#endif
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index b73e3c0056c..d5276c012f7 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -61,7 +61,7 @@
#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
#define SN_SAL_UART_FIFO_DEPTH 16
-#define SN_SAL_UART_FIFO_SPEED_CPS 9600/10
+#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10)
/* sn_transmit_chars() calling args */
#define TRANSMIT_BUFFERED 0
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 539c933b335..315a9333ca3 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -1066,7 +1066,7 @@ static int qe_uart_verify_port(struct uart_port *port,
if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
return -EINVAL;
- if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ if (ser->irq < 0 || ser->irq >= nr_irqs)
return -EINVAL;
if (ser->baud_base < 9600)
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index a96f4a8cfeb..6a025cefe6d 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for the SuperH specific drivers.
#
-
obj-$(CONFIG_SUPERHYWAY) += superhyway/
obj-$(CONFIG_MAPLE) += maple/
+obj-y += intc.o
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
new file mode 100644
index 00000000000..58d24c5a76c
--- /dev/null
+++ b/drivers/sh/intc.c
@@ -0,0 +1,713 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ *
+ * Based on intc2.c and ipr.c
+ *
+ * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000 Kazumoto Kojima
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Copyright (C) 2005, 2006 Paul Mundt
+ *
+ * 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/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+#include <linux/sh_intc.h>
+
+#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
+ ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
+ ((addr_e) << 16) | ((addr_d << 24)))
+
+#define _INTC_SHIFT(h) (h & 0x1f)
+#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
+#define _INTC_FN(h) ((h >> 9) & 0xf)
+#define _INTC_MODE(h) ((h >> 13) & 0x7)
+#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
+#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
+
+struct intc_handle_int {
+ unsigned int irq;
+ unsigned long handle;
+};
+
+struct intc_desc_int {
+ unsigned long *reg;
+#ifdef CONFIG_SMP
+ unsigned long *smp;
+#endif
+ unsigned int nr_reg;
+ struct intc_handle_int *prio;
+ unsigned int nr_prio;
+ struct intc_handle_int *sense;
+ unsigned int nr_sense;
+ struct irq_chip chip;
+};
+
+#ifdef CONFIG_SMP
+#define IS_SMP(x) x.smp
+#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
+#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
+#else
+#define IS_SMP(x) 0
+#define INTC_REG(d, x, c) (d->reg[(x)])
+#define SMP_NR(d, x) 1
+#endif
+
+static unsigned int intc_prio_level[NR_IRQS]; /* for now */
+#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
+static unsigned long ack_handle[NR_IRQS];
+#endif
+
+static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
+{
+ struct irq_chip *chip = get_irq_chip(irq);
+ return (void *)((char *)chip - offsetof(struct intc_desc_int, chip));
+}
+
+static inline unsigned int set_field(unsigned int value,
+ unsigned int field_value,
+ unsigned int handle)
+{
+ unsigned int width = _INTC_WIDTH(handle);
+ unsigned int shift = _INTC_SHIFT(handle);
+
+ value &= ~(((1 << width) - 1) << shift);
+ value |= field_value << shift;
+ return value;
+}
+
+static void write_8(unsigned long addr, unsigned long h, unsigned long data)
+{
+ __raw_writeb(set_field(0, data, h), addr);
+}
+
+static void write_16(unsigned long addr, unsigned long h, unsigned long data)
+{
+ __raw_writew(set_field(0, data, h), addr);
+}
+
+static void write_32(unsigned long addr, unsigned long h, unsigned long data)
+{
+ __raw_writel(set_field(0, data, h), addr);
+}
+
+static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ __raw_writeb(set_field(__raw_readb(addr), data, h), addr);
+ local_irq_restore(flags);
+}
+
+static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ __raw_writew(set_field(__raw_readw(addr), data, h), addr);
+ local_irq_restore(flags);
+}
+
+static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ __raw_writel(set_field(__raw_readl(addr), data, h), addr);
+ local_irq_restore(flags);
+}
+
+enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 };
+
+static void (*intc_reg_fns[])(unsigned long addr,
+ unsigned long h,
+ unsigned long data) = {
+ [REG_FN_WRITE_BASE + 0] = write_8,
+ [REG_FN_WRITE_BASE + 1] = write_16,
+ [REG_FN_WRITE_BASE + 3] = write_32,
+ [REG_FN_MODIFY_BASE + 0] = modify_8,
+ [REG_FN_MODIFY_BASE + 1] = modify_16,
+ [REG_FN_MODIFY_BASE + 3] = modify_32,
+};
+
+enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
+ MODE_MASK_REG, /* Bit(s) set -> interrupt disabled */
+ MODE_DUAL_REG, /* Two registers, set bit to enable / disable */
+ MODE_PRIO_REG, /* Priority value written to enable interrupt */
+ MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */
+};
+
+static void intc_mode_field(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
+{
+ fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
+}
+
+static void intc_mode_zero(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
+{
+ fn(addr, handle, 0);
+}
+
+static void intc_mode_prio(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
+{
+ fn(addr, handle, intc_prio_level[irq]);
+}
+
+static void (*intc_enable_fns[])(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_field,
+ [MODE_MASK_REG] = intc_mode_zero,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_prio,
+ [MODE_PCLR_REG] = intc_mode_prio,
+};
+
+static void (*intc_disable_fns[])(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_zero,
+ [MODE_MASK_REG] = intc_mode_field,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_zero,
+ [MODE_PCLR_REG] = intc_mode_field,
+};
+
+static inline void _intc_enable(unsigned int irq, unsigned long handle)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long addr;
+ unsigned int cpu;
+
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+ intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
+}
+
+static void intc_enable(unsigned int irq)
+{
+ _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
+}
+
+static void intc_disable(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = (unsigned long) get_irq_chip_data(irq);
+ unsigned long addr;
+ unsigned int cpu;
+
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+ intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
+}
+
+#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
+static void intc_mask_ack(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = ack_handle[irq];
+ unsigned long addr;
+
+ intc_disable(irq);
+
+ /* read register and write zero only to the assocaited bit */
+
+ if (handle) {
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+ switch (_INTC_FN(handle)) {
+ case REG_FN_MODIFY_BASE + 0: /* 8bit */
+ __raw_readb(addr);
+ __raw_writeb(0xff ^ set_field(0, 1, handle), addr);
+ break;
+ case REG_FN_MODIFY_BASE + 1: /* 16bit */
+ __raw_readw(addr);
+ __raw_writew(0xffff ^ set_field(0, 1, handle), addr);
+ break;
+ case REG_FN_MODIFY_BASE + 3: /* 32bit */
+ __raw_readl(addr);
+ __raw_writel(0xffffffff ^ set_field(0, 1, handle), addr);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ }
+}
+#endif
+
+static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
+ unsigned int nr_hp,
+ unsigned int irq)
+{
+ int i;
+
+ /* this doesn't scale well, but...
+ *
+ * this function should only be used for cerain uncommon
+ * operations such as intc_set_priority() and intc_set_sense()
+ * and in those rare cases performance doesn't matter that much.
+ * keeping the memory footprint low is more important.
+ *
+ * one rather simple way to speed this up and still keep the
+ * memory footprint down is to make sure the array is sorted
+ * and then perform a bisect to lookup the irq.
+ */
+
+ for (i = 0; i < nr_hp; i++) {
+ if ((hp + i)->irq != irq)
+ continue;
+
+ return hp + i;
+ }
+
+ return NULL;
+}
+
+int intc_set_priority(unsigned int irq, unsigned int prio)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ struct intc_handle_int *ihp;
+
+ if (!intc_prio_level[irq] || prio <= 1)
+ return -EINVAL;
+
+ ihp = intc_find_irq(d->prio, d->nr_prio, irq);
+ if (ihp) {
+ if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
+ return -EINVAL;
+
+ intc_prio_level[irq] = prio;
+
+ /*
+ * only set secondary masking method directly
+ * primary masking method is using intc_prio_level[irq]
+ * priority level will be set during next enable()
+ */
+
+ if (_INTC_FN(ihp->handle) != REG_FN_ERR)
+ _intc_enable(irq, ihp->handle);
+ }
+ return 0;
+}
+
+#define VALID(x) (x | 0x80)
+
+static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+ [IRQ_TYPE_EDGE_FALLING] = VALID(0),
+ [IRQ_TYPE_EDGE_RISING] = VALID(1),
+ [IRQ_TYPE_LEVEL_LOW] = VALID(2),
+ /* SH7706, SH7707 and SH7709 do not support high level triggered */
+#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7709)
+ [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
+#endif
+};
+
+static int intc_set_sense(unsigned int irq, unsigned int type)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
+ struct intc_handle_int *ihp;
+ unsigned long addr;
+
+ if (!value)
+ return -EINVAL;
+
+ ihp = intc_find_irq(d->sense, d->nr_sense, irq);
+ if (ihp) {
+ addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
+ intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
+ }
+ return 0;
+}
+
+static unsigned int __init intc_get_reg(struct intc_desc_int *d,
+ unsigned long address)
+{
+ unsigned int k;
+
+ for (k = 0; k < d->nr_reg; k++) {
+ if (d->reg[k] == address)
+ return k;
+ }
+
+ BUG();
+ return 0;
+}
+
+static intc_enum __init intc_grp_id(struct intc_desc *desc,
+ intc_enum enum_id)
+{
+ struct intc_group *g = desc->groups;
+ unsigned int i, j;
+
+ for (i = 0; g && enum_id && i < desc->nr_groups; i++) {
+ g = desc->groups + i;
+
+ for (j = 0; g->enum_ids[j]; j++) {
+ if (g->enum_ids[j] != enum_id)
+ continue;
+
+ return g->enum_id;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int __init intc_mask_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps)
+{
+ struct intc_mask_reg *mr = desc->mask_regs;
+ unsigned int i, j, fn, mode;
+ unsigned long reg_e, reg_d;
+
+ for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
+ mr = desc->mask_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+ if (mr->enum_ids[j] != enum_id)
+ continue;
+
+ if (mr->set_reg && mr->clr_reg) {
+ fn = REG_FN_WRITE_BASE;
+ mode = MODE_DUAL_REG;
+ reg_e = mr->clr_reg;
+ reg_d = mr->set_reg;
+ } else {
+ fn = REG_FN_MODIFY_BASE;
+ if (mr->set_reg) {
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->set_reg;
+ reg_d = mr->set_reg;
+ } else {
+ mode = MODE_MASK_REG;
+ reg_e = mr->clr_reg;
+ reg_d = mr->clr_reg;
+ }
+ }
+
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - j);
+ }
+ }
+
+ if (do_grps)
+ return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
+
+ return 0;
+}
+
+static unsigned int __init intc_prio_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps)
+{
+ struct intc_prio_reg *pr = desc->prio_regs;
+ unsigned int i, j, fn, mode, bit;
+ unsigned long reg_e, reg_d;
+
+ for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
+ pr = desc->prio_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) {
+ if (pr->enum_ids[j] != enum_id)
+ continue;
+
+ if (pr->set_reg && pr->clr_reg) {
+ fn = REG_FN_WRITE_BASE;
+ mode = MODE_PCLR_REG;
+ reg_e = pr->set_reg;
+ reg_d = pr->clr_reg;
+ } else {
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_PRIO_REG;
+ if (!pr->set_reg)
+ BUG();
+ reg_e = pr->set_reg;
+ reg_d = pr->set_reg;
+ }
+
+ fn += (pr->reg_width >> 3) - 1;
+
+ BUG_ON((j + 1) * pr->field_width > pr->reg_width);
+
+ bit = pr->reg_width - ((j + 1) * pr->field_width);
+
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ pr->field_width, bit);
+ }
+ }
+
+ if (do_grps)
+ return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);
+
+ return 0;
+}
+
+#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
+static unsigned int __init intc_ack_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_mask_reg *mr = desc->ack_regs;
+ unsigned int i, j, fn, mode;
+ unsigned long reg_e, reg_d;
+
+ for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) {
+ mr = desc->ack_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+ if (mr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->set_reg;
+ reg_d = mr->set_reg;
+
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - j);
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static unsigned int __init intc_sense_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_sense_reg *sr = desc->sense_regs;
+ unsigned int i, j, fn, bit;
+
+ for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) {
+ sr = desc->sense_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+ if (sr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ fn += (sr->reg_width >> 3) - 1;
+
+ BUG_ON((j + 1) * sr->field_width > sr->reg_width);
+
+ bit = sr->reg_width - ((j + 1) * sr->field_width);
+
+ return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
+ 0, sr->field_width, bit);
+ }
+ }
+
+ return 0;
+}
+
+static void __init intc_register_irq(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
+ unsigned int irq)
+{
+ struct intc_handle_int *hp;
+ unsigned int data[2], primary;
+
+ /* Prefer single interrupt source bitmap over other combinations:
+ * 1. bitmap, single interrupt source
+ * 2. priority, single interrupt source
+ * 3. bitmap, multiple interrupt sources (groups)
+ * 4. priority, multiple interrupt sources (groups)
+ */
+
+ data[0] = intc_mask_data(desc, d, enum_id, 0);
+ data[1] = intc_prio_data(desc, d, enum_id, 0);
+
+ primary = 0;
+ if (!data[0] && data[1])
+ primary = 1;
+
+ data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
+ data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
+
+ if (!data[primary])
+ primary ^= 1;
+
+ BUG_ON(!data[primary]); /* must have primary masking method */
+
+ disable_irq_nosync(irq);
+ set_irq_chip_and_handler_name(irq, &d->chip,
+ handle_level_irq, "level");
+ set_irq_chip_data(irq, (void *)data[primary]);
+
+ /* set priority level
+ * - this needs to be at least 2 for 5-bit priorities on 7780
+ */
+ intc_prio_level[irq] = 2;
+
+ /* enable secondary masking method if present */
+ if (data[!primary])
+ _intc_enable(irq, data[!primary]);
+
+ /* add irq to d->prio list if priority is available */
+ if (data[1]) {
+ hp = d->prio + d->nr_prio;
+ hp->irq = irq;
+ hp->handle = data[1];
+
+ if (primary) {
+ /*
+ * only secondary priority should access registers, so
+ * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
+ */
+
+ hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
+ hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
+ }
+ d->nr_prio++;
+ }
+
+ /* add irq to d->sense list if sense is available */
+ data[0] = intc_sense_data(desc, d, enum_id);
+ if (data[0]) {
+ (d->sense + d->nr_sense)->irq = irq;
+ (d->sense + d->nr_sense)->handle = data[0];
+ d->nr_sense++;
+ }
+
+ /* irq should be disabled by default */
+ d->chip.mask(irq);
+
+#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
+ if (desc->ack_regs)
+ ack_handle[irq] = intc_ack_data(desc, d, enum_id);
+#endif
+}
+
+static unsigned int __init save_reg(struct intc_desc_int *d,
+ unsigned int cnt,
+ unsigned long value,
+ unsigned int smp)
+{
+ if (value) {
+ d->reg[cnt] = value;
+#ifdef CONFIG_SMP
+ d->smp[cnt] = smp;
+#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void __init register_intc_controller(struct intc_desc *desc)
+{
+ unsigned int i, k, smp;
+ struct intc_desc_int *d;
+
+ d = alloc_bootmem(sizeof(*d));
+
+ d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0;
+ d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
+ d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
+
+#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
+ d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0;
+#endif
+ d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
+#ifdef CONFIG_SMP
+ d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
+#endif
+ k = 0;
+
+ if (desc->mask_regs) {
+ for (i = 0; i < desc->nr_mask_regs; i++) {
+ smp = IS_SMP(desc->mask_regs[i]);
+ k += save_reg(d, k, desc->mask_regs[i].set_reg, smp);
+ k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp);
+ }
+ }
+
+ if (desc->prio_regs) {
+ d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio));
+
+ for (i = 0; i < desc->nr_prio_regs; i++) {
+ smp = IS_SMP(desc->prio_regs[i]);
+ k += save_reg(d, k, desc->prio_regs[i].set_reg, smp);
+ k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp);
+ }
+ }
+
+ if (desc->sense_regs) {
+ d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense));
+
+ for (i = 0; i < desc->nr_sense_regs; i++) {
+ k += save_reg(d, k, desc->sense_regs[i].reg, 0);
+ }
+ }
+
+ d->chip.name = desc->name;
+ d->chip.mask = intc_disable;
+ d->chip.unmask = intc_enable;
+ d->chip.mask_ack = intc_disable;
+ d->chip.set_type = intc_set_sense;
+
+#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
+ if (desc->ack_regs) {
+ for (i = 0; i < desc->nr_ack_regs; i++)
+ k += save_reg(d, k, desc->ack_regs[i].set_reg, 0);
+
+ d->chip.mask_ack = intc_mask_ack;
+ }
+#endif
+
+ BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
+
+ for (i = 0; i < desc->nr_vectors; i++) {
+ struct intc_vect *vect = desc->vectors + i;
+
+ intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
+ }
+}
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 2a79decd7df..c4eff44c9f2 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -43,4 +43,8 @@ source "drivers/staging/echo/Kconfig"
source "drivers/staging/at76_usb/Kconfig"
+source "drivers/staging/pcc-acpi/Kconfig"
+
+source "drivers/staging/poch/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 325bca4f71c..7cb8701d96d 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -13,3 +13,5 @@ obj-$(CONFIG_W35UND) += winbond/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_USB_ATMEL) += at76_usb/
+obj-$(CONFIG_PCC_ACPI) += pcc-acpi/
+obj-$(CONFIG_POCH) += poch/
diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c
index 52df0c66518..174e2bec922 100644
--- a/drivers/staging/at76_usb/at76_usb.c
+++ b/drivers/staging/at76_usb/at76_usb.c
@@ -2319,9 +2319,11 @@ static int at76_iw_handler_get_scan(struct net_device *netdev,
if (!iwe)
return -ENOMEM;
- if (priv->scan_state != SCAN_COMPLETED)
+ if (priv->scan_state != SCAN_COMPLETED) {
/* scan not yet finished */
+ kfree(iwe);
return -EAGAIN;
+ }
spin_lock_irqsave(&priv->bss_list_spinlock, flags);
diff --git a/drivers/staging/echo/bit_operations.h b/drivers/staging/echo/bit_operations.h
index b32f4bf9939..cecdcf3fd75 100644
--- a/drivers/staging/echo/bit_operations.h
+++ b/drivers/staging/echo/bit_operations.h
@@ -30,114 +30,98 @@
#if !defined(_BIT_OPERATIONS_H_)
#define _BIT_OPERATIONS_H_
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#if defined(__i386__) || defined(__x86_64__)
/*! \brief Find the bit position of the highest set bit in a word
\param bits The word to be searched
\return The bit number of the highest set bit, or -1 if the word is zero. */
static __inline__ int top_bit(unsigned int bits)
{
- int res;
-
- __asm__ (" xorl %[res],%[res];\n"
- " decl %[res];\n"
- " bsrl %[bits],%[res]\n"
- : [res] "=&r" (res)
- : [bits] "rm" (bits));
- return res;
+ int res;
+
+ __asm__(" xorl %[res],%[res];\n"
+ " decl %[res];\n"
+ " bsrl %[bits],%[res]\n"
+ :[res] "=&r" (res)
+ :[bits] "rm"(bits)
+ );
+ return res;
}
-/*- End of function --------------------------------------------------------*/
/*! \brief Find the bit position of the lowest set bit in a word
\param bits The word to be searched
\return The bit number of the lowest set bit, or -1 if the word is zero. */
static __inline__ int bottom_bit(unsigned int bits)
{
- int res;
-
- __asm__ (" xorl %[res],%[res];\n"
- " decl %[res];\n"
- " bsfl %[bits],%[res]\n"
- : [res] "=&r" (res)
- : [bits] "rm" (bits));
- return res;
+ int res;
+
+ __asm__(" xorl %[res],%[res];\n"
+ " decl %[res];\n"
+ " bsfl %[bits],%[res]\n"
+ :[res] "=&r" (res)
+ :[bits] "rm"(bits)
+ );
+ return res;
}
-/*- End of function --------------------------------------------------------*/
#else
static __inline__ int top_bit(unsigned int bits)
{
- int i;
-
- if (bits == 0)
- return -1;
- i = 0;
- if (bits & 0xFFFF0000)
- {
- bits &= 0xFFFF0000;
- i += 16;
- }
- if (bits & 0xFF00FF00)
- {
- bits &= 0xFF00FF00;
- i += 8;
- }
- if (bits & 0xF0F0F0F0)
- {
- bits &= 0xF0F0F0F0;
- i += 4;
- }
- if (bits & 0xCCCCCCCC)
- {
- bits &= 0xCCCCCCCC;
- i += 2;
- }
- if (bits & 0xAAAAAAAA)
- {
- bits &= 0xAAAAAAAA;
- i += 1;
- }
- return i;
+ int i;
+
+ if (bits == 0)
+ return -1;
+ i = 0;
+ if (bits & 0xFFFF0000) {
+ bits &= 0xFFFF0000;
+ i += 16;
+ }
+ if (bits & 0xFF00FF00) {
+ bits &= 0xFF00FF00;
+ i += 8;
+ }
+ if (bits & 0xF0F0F0F0) {
+ bits &= 0xF0F0F0F0;
+ i += 4;
+ }
+ if (bits & 0xCCCCCCCC) {
+ bits &= 0xCCCCCCCC;
+ i += 2;
+ }
+ if (bits & 0xAAAAAAAA) {
+ bits &= 0xAAAAAAAA;
+ i += 1;
+ }
+ return i;
}
-/*- End of function --------------------------------------------------------*/
static __inline__ int bottom_bit(unsigned int bits)
{
- int i;
-
- if (bits == 0)
- return -1;
- i = 32;
- if (bits & 0x0000FFFF)
- {
- bits &= 0x0000FFFF;
- i -= 16;
- }
- if (bits & 0x00FF00FF)
- {
- bits &= 0x00FF00FF;
- i -= 8;
- }
- if (bits & 0x0F0F0F0F)
- {
- bits &= 0x0F0F0F0F;
- i -= 4;
- }
- if (bits & 0x33333333)
- {
- bits &= 0x33333333;
- i -= 2;
- }
- if (bits & 0x55555555)
- {
- bits &= 0x55555555;
- i -= 1;
- }
- return i;
+ int i;
+
+ if (bits == 0)
+ return -1;
+ i = 32;
+ if (bits & 0x0000FFFF) {
+ bits &= 0x0000FFFF;
+ i -= 16;
+ }
+ if (bits & 0x00FF00FF) {
+ bits &= 0x00FF00FF;
+ i -= 8;
+ }
+ if (bits & 0x0F0F0F0F) {
+ bits &= 0x0F0F0F0F;
+ i -= 4;
+ }
+ if (bits & 0x33333333) {
+ bits &= 0x33333333;
+ i -= 2;
+ }
+ if (bits & 0x55555555) {
+ bits &= 0x55555555;
+ i -= 1;
+ }
+ return i;
}
-/*- End of function --------------------------------------------------------*/
#endif
/*! \brief Bit reverse a byte.
@@ -146,16 +130,16 @@ static __inline__ int bottom_bit(unsigned int bits)
static __inline__ uint8_t bit_reverse8(uint8_t x)
{
#if defined(__i386__) || defined(__x86_64__)
- /* If multiply is fast */
- return ((x*0x0802U & 0x22110U) | (x*0x8020U & 0x88440U))*0x10101U >> 16;
+ /* If multiply is fast */
+ return ((x * 0x0802U & 0x22110U) | (x * 0x8020U & 0x88440U)) *
+ 0x10101U >> 16;
#else
- /* If multiply is slow, but we have a barrel shifter */
- x = (x >> 4) | (x << 4);
- x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
- return ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
+ /* If multiply is slow, but we have a barrel shifter */
+ x = (x >> 4) | (x << 4);
+ x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
+ return ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
#endif
}
-/*- End of function --------------------------------------------------------*/
/*! \brief Bit reverse a 16 bit word.
\param data The word to be reversed.
@@ -193,9 +177,8 @@ uint16_t make_mask16(uint16_t x);
\return The word with the single set bit. */
static __inline__ uint32_t least_significant_one32(uint32_t x)
{
- return (x & (-(int32_t) x));
+ return (x & (-(int32_t) x));
}
-/*- End of function --------------------------------------------------------*/
/*! \brief Find the most significant one in a word, and return a word
with just that bit set.
@@ -204,50 +187,42 @@ static __inline__ uint32_t least_significant_one32(uint32_t x)
static __inline__ uint32_t most_significant_one32(uint32_t x)
{
#if defined(__i386__) || defined(__x86_64__)
- return 1 << top_bit(x);
+ return 1 << top_bit(x);
#else
- x = make_mask32(x);
- return (x ^ (x >> 1));
+ x = make_mask32(x);
+ return (x ^ (x >> 1));
#endif
}
-/*- End of function --------------------------------------------------------*/
/*! \brief Find the parity of a byte.
\param x The byte to be checked.
\return 1 for odd, or 0 for even. */
static __inline__ int parity8(uint8_t x)
{
- x = (x ^ (x >> 4)) & 0x0F;
- return (0x6996 >> x) & 1;
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
}
-/*- End of function --------------------------------------------------------*/
/*! \brief Find the parity of a 16 bit word.
\param x The word to be checked.
\return 1 for odd, or 0 for even. */
static __inline__ int parity16(uint16_t x)
{
- x ^= (x >> 8);
- x = (x ^ (x >> 4)) & 0x0F;
- return (0x6996 >> x) & 1;
+ x ^= (x >> 8);
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
}
-/*- End of function --------------------------------------------------------*/
/*! \brief Find the parity of a 32 bit word.
\param x The word to be checked.
\return 1 for odd, or 0 for even. */
static __inline__ int parity32(uint32_t x)
{
- x ^= (x >> 16);
- x ^= (x >> 8);
- x = (x ^ (x >> 4)) & 0x0F;
- return (0x6996 >> x) & 1;
+ x ^= (x >> 16);
+ x ^= (x >> 8);
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
}
-/*- End of function --------------------------------------------------------*/
-
-#ifdef __cplusplus
-}
-#endif
#endif
/*- End of file ------------------------------------------------------------*/
diff --git a/drivers/staging/echo/echo.c b/drivers/staging/echo/echo.c
index 4a281b14fc5..b8f2c5e9dee 100644
--- a/drivers/staging/echo/echo.c
+++ b/drivers/staging/echo/echo.c
@@ -74,7 +74,6 @@
Steve also has some nice notes on echo cancellers in echo.h
-
References:
[1] Ochiai, Areseki, and Ogihara, "Echo Canceller with Two Echo
@@ -105,20 +104,18 @@
Mark, Pawel, and Pavel.
*/
-#include <linux/kernel.h> /* We're doing kernel work */
+#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#define malloc(a) kmalloc((a), GFP_KERNEL)
-#define free(a) kfree(a)
#include "bit_operations.h"
#include "echo.h"
#define MIN_TX_POWER_FOR_ADAPTION 64
#define MIN_RX_POWER_FOR_ADAPTION 64
-#define DTD_HANGOVER 600 /* 600 samples, or 75ms */
-#define DC_LOG2BETA 3 /* log2() of DC filter Beta */
+#define DTD_HANGOVER 600 /* 600 samples, or 75ms */
+#define DC_LOG2BETA 3 /* log2() of DC filter Beta */
/*-----------------------------------------------------------------------*\
FUNCTIONS
@@ -126,59 +123,58 @@
/* adapting coeffs using the traditional stochastic descent (N)LMS algorithm */
-
-#ifdef __BLACKFIN_ASM__
-static void __inline__ lms_adapt_bg(echo_can_state_t *ec, int clean, int shift)
+#ifdef __bfin__
+static void __inline__ lms_adapt_bg(struct oslec_state *ec, int clean,
+ int shift)
{
- int i, j;
- int offset1;
- int offset2;
- int factor;
- int exp;
- int16_t *phist;
- int n;
-
- if (shift > 0)
- factor = clean << shift;
- else
- factor = clean >> -shift;
-
- /* Update the FIR taps */
-
- offset2 = ec->curr_pos;
- offset1 = ec->taps - offset2;
- phist = &ec->fir_state_bg.history[offset2];
-
- /* st: and en: help us locate the assembler in echo.s */
-
- //asm("st:");
- n = ec->taps;
- for (i = 0, j = offset2; i < n; i++, j++)
- {
- exp = *phist++ * factor;
- ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15);
- }
- //asm("en:");
-
- /* Note the asm for the inner loop above generated by Blackfin gcc
- 4.1.1 is pretty good (note even parallel instructions used):
-
- R0 = W [P0++] (X);
- R0 *= R2;
- R0 = R0 + R3 (NS) ||
- R1 = W [P1] (X) ||
- nop;
- R0 >>>= 15;
- R0 = R0 + R1;
- W [P1++] = R0;
-
- A block based update algorithm would be much faster but the
- above can't be improved on much. Every instruction saved in
- the loop above is 2 MIPs/ch! The for loop above is where the
- Blackfin spends most of it's time - about 17 MIPs/ch measured
- with speedtest.c with 256 taps (32ms). Write-back and
- Write-through cache gave about the same performance.
- */
+ int i, j;
+ int offset1;
+ int offset2;
+ int factor;
+ int exp;
+ int16_t *phist;
+ int n;
+
+ if (shift > 0)
+ factor = clean << shift;
+ else
+ factor = clean >> -shift;
+
+ /* Update the FIR taps */
+
+ offset2 = ec->curr_pos;
+ offset1 = ec->taps - offset2;
+ phist = &ec->fir_state_bg.history[offset2];
+
+ /* st: and en: help us locate the assembler in echo.s */
+
+ //asm("st:");
+ n = ec->taps;
+ for (i = 0, j = offset2; i < n; i++, j++) {
+ exp = *phist++ * factor;
+ ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
+ }
+ //asm("en:");
+
+ /* Note the asm for the inner loop above generated by Blackfin gcc
+ 4.1.1 is pretty good (note even parallel instructions used):
+
+ R0 = W [P0++] (X);
+ R0 *= R2;
+ R0 = R0 + R3 (NS) ||
+ R1 = W [P1] (X) ||
+ nop;
+ R0 >>>= 15;
+ R0 = R0 + R1;
+ W [P1++] = R0;
+
+ A block based update algorithm would be much faster but the
+ above can't be improved on much. Every instruction saved in
+ the loop above is 2 MIPs/ch! The for loop above is where the
+ Blackfin spends most of it's time - about 17 MIPs/ch measured
+ with speedtest.c with 256 taps (32ms). Write-back and
+ Write-through cache gave about the same performance.
+ */
}
/*
@@ -200,392 +196,393 @@ static void __inline__ lms_adapt_bg(echo_can_state_t *ec, int clean, int shift)
*/
#else
-static __inline__ void lms_adapt_bg(echo_can_state_t *ec, int clean, int shift)
+static __inline__ void lms_adapt_bg(struct oslec_state *ec, int clean,
+ int shift)
{
- int i;
-
- int offset1;
- int offset2;
- int factor;
- int exp;
-
- if (shift > 0)
- factor = clean << shift;
- else
- factor = clean >> -shift;
-
- /* Update the FIR taps */
-
- offset2 = ec->curr_pos;
- offset1 = ec->taps - offset2;
-
- for (i = ec->taps - 1; i >= offset1; i--)
- {
- exp = (ec->fir_state_bg.history[i - offset1]*factor);
- ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15);
- }
- for ( ; i >= 0; i--)
- {
- exp = (ec->fir_state_bg.history[i + offset2]*factor);
- ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15);
- }
+ int i;
+
+ int offset1;
+ int offset2;
+ int factor;
+ int exp;
+
+ if (shift > 0)
+ factor = clean << shift;
+ else
+ factor = clean >> -shift;
+
+ /* Update the FIR taps */
+
+ offset2 = ec->curr_pos;
+ offset1 = ec->taps - offset2;
+
+ for (i = ec->taps - 1; i >= offset1; i--) {
+ exp = (ec->fir_state_bg.history[i - offset1] * factor);
+ ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
+ }
+ for (; i >= 0; i--) {
+ exp = (ec->fir_state_bg.history[i + offset2] * factor);
+ ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
+ }
}
#endif
-/*- End of function --------------------------------------------------------*/
-
-echo_can_state_t *echo_can_create(int len, int adaption_mode)
+struct oslec_state *oslec_create(int len, int adaption_mode)
{
- echo_can_state_t *ec;
- int i;
- int j;
-
- ec = kmalloc(sizeof(*ec), GFP_KERNEL);
- if (ec == NULL)
- return NULL;
- memset(ec, 0, sizeof(*ec));
-
- ec->taps = len;
- ec->log2taps = top_bit(len);
- ec->curr_pos = ec->taps - 1;
-
- for (i = 0; i < 2; i++)
- {
- if ((ec->fir_taps16[i] = (int16_t *) malloc((ec->taps)*sizeof(int16_t))) == NULL)
- {
- for (j = 0; j < i; j++)
- kfree(ec->fir_taps16[j]);
- kfree(ec);
- return NULL;
- }
- memset(ec->fir_taps16[i], 0, (ec->taps)*sizeof(int16_t));
- }
-
- fir16_create(&ec->fir_state,
- ec->fir_taps16[0],
- ec->taps);
- fir16_create(&ec->fir_state_bg,
- ec->fir_taps16[1],
- ec->taps);
-
- for(i=0; i<5; i++) {
- ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0;
- }
-
- ec->cng_level = 1000;
- echo_can_adaption_mode(ec, adaption_mode);
-
- ec->snapshot = (int16_t*)malloc(ec->taps*sizeof(int16_t));
- memset(ec->snapshot, 0, sizeof(int16_t)*ec->taps);
-
- ec->cond_met = 0;
- ec->Pstates = 0;
- ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
- ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
- ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
- ec->Lbgn = ec->Lbgn_acc = 0;
- ec->Lbgn_upper = 200;
- ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
-
- return ec;
+ struct oslec_state *ec;
+ int i;
+
+ ec = kzalloc(sizeof(*ec), GFP_KERNEL);
+ if (!ec)
+ return NULL;
+
+ ec->taps = len;
+ ec->log2taps = top_bit(len);
+ ec->curr_pos = ec->taps - 1;
+
+ for (i = 0; i < 2; i++) {
+ ec->fir_taps16[i] =
+ kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
+ if (!ec->fir_taps16[i])
+ goto error_oom;
+ }
+
+ fir16_create(&ec->fir_state, ec->fir_taps16[0], ec->taps);
+ fir16_create(&ec->fir_state_bg, ec->fir_taps16[1], ec->taps);
+
+ for (i = 0; i < 5; i++) {
+ ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0;
+ }
+
+ ec->cng_level = 1000;
+ oslec_adaption_mode(ec, adaption_mode);
+
+ ec->snapshot = kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
+ if (!ec->snapshot)
+ goto error_oom;
+
+ ec->cond_met = 0;
+ ec->Pstates = 0;
+ ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
+ ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
+ ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
+ ec->Lbgn = ec->Lbgn_acc = 0;
+ ec->Lbgn_upper = 200;
+ ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
+
+ return ec;
+
+ error_oom:
+ for (i = 0; i < 2; i++)
+ kfree(ec->fir_taps16[i]);
+
+ kfree(ec);
+ return NULL;
}
-/*- End of function --------------------------------------------------------*/
-void echo_can_free(echo_can_state_t *ec)
+EXPORT_SYMBOL_GPL(oslec_create);
+
+void oslec_free(struct oslec_state *ec)
{
int i;
fir16_free(&ec->fir_state);
fir16_free(&ec->fir_state_bg);
- for (i = 0; i < 2; i++)
+ for (i = 0; i < 2; i++)
kfree(ec->fir_taps16[i]);
kfree(ec->snapshot);
kfree(ec);
}
-/*- End of function --------------------------------------------------------*/
-void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode)
+EXPORT_SYMBOL_GPL(oslec_free);
+
+void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode)
{
- ec->adaption_mode = adaption_mode;
+ ec->adaption_mode = adaption_mode;
}
-/*- End of function --------------------------------------------------------*/
-void echo_can_flush(echo_can_state_t *ec)
+EXPORT_SYMBOL_GPL(oslec_adaption_mode);
+
+void oslec_flush(struct oslec_state *ec)
{
- int i;
+ int i;
- ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
- ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
- ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
+ ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
+ ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
+ ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
- ec->Lbgn = ec->Lbgn_acc = 0;
- ec->Lbgn_upper = 200;
- ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
+ ec->Lbgn = ec->Lbgn_acc = 0;
+ ec->Lbgn_upper = 200;
+ ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
- ec->nonupdate_dwell = 0;
+ ec->nonupdate_dwell = 0;
- fir16_flush(&ec->fir_state);
- fir16_flush(&ec->fir_state_bg);
- ec->fir_state.curr_pos = ec->taps - 1;
- ec->fir_state_bg.curr_pos = ec->taps - 1;
- for (i = 0; i < 2; i++)
- memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t));
+ fir16_flush(&ec->fir_state);
+ fir16_flush(&ec->fir_state_bg);
+ ec->fir_state.curr_pos = ec->taps - 1;
+ ec->fir_state_bg.curr_pos = ec->taps - 1;
+ for (i = 0; i < 2; i++)
+ memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
- ec->curr_pos = ec->taps - 1;
- ec->Pstates = 0;
+ ec->curr_pos = ec->taps - 1;
+ ec->Pstates = 0;
}
-/*- End of function --------------------------------------------------------*/
-void echo_can_snapshot(echo_can_state_t *ec) {
- memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps*sizeof(int16_t));
+EXPORT_SYMBOL_GPL(oslec_flush);
+
+void oslec_snapshot(struct oslec_state *ec)
+{
+ memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps * sizeof(int16_t));
}
-/*- End of function --------------------------------------------------------*/
+
+EXPORT_SYMBOL_GPL(oslec_snapshot);
/* Dual Path Echo Canceller ------------------------------------------------*/
-int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx)
+int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx)
{
- int32_t echo_value;
- int clean_bg;
- int tmp, tmp1;
-
- /* Input scaling was found be required to prevent problems when tx
- starts clipping. Another possible way to handle this would be the
- filter coefficent scaling. */
-
- ec->tx = tx; ec->rx = rx;
- tx >>=1;
- rx >>=1;
-
- /*
- Filter DC, 3dB point is 160Hz (I think), note 32 bit precision required
- otherwise values do not track down to 0. Zero at DC, Pole at (1-Beta)
- only real axis. Some chip sets (like Si labs) don't need
- this, but something like a $10 X100P card does. Any DC really slows
- down convergence.
-
- Note: removes some low frequency from the signal, this reduces
- the speech quality when listening to samples through headphones
- but may not be obvious through a telephone handset.
-
- Note that the 3dB frequency in radians is approx Beta, e.g. for
- Beta = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz.
- */
-
- if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) {
- tmp = rx << 15;
+ int32_t echo_value;
+ int clean_bg;
+ int tmp, tmp1;
+
+ /* Input scaling was found be required to prevent problems when tx
+ starts clipping. Another possible way to handle this would be the
+ filter coefficent scaling. */
+
+ ec->tx = tx;
+ ec->rx = rx;
+ tx >>= 1;
+ rx >>= 1;
+
+ /*
+ Filter DC, 3dB point is 160Hz (I think), note 32 bit precision required
+ otherwise values do not track down to 0. Zero at DC, Pole at (1-Beta)
+ only real axis. Some chip sets (like Si labs) don't need
+ this, but something like a $10 X100P card does. Any DC really slows
+ down convergence.
+
+ Note: removes some low frequency from the signal, this reduces
+ the speech quality when listening to samples through headphones
+ but may not be obvious through a telephone handset.
+
+ Note that the 3dB frequency in radians is approx Beta, e.g. for
+ Beta = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz.
+ */
+
+ if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) {
+ tmp = rx << 15;
#if 1
- /* Make sure the gain of the HPF is 1.0. This can still saturate a little under
- impulse conditions, and it might roll to 32768 and need clipping on sustained peak
- level signals. However, the scale of such clipping is small, and the error due to
- any saturation should not markedly affect the downstream processing. */
- tmp -= (tmp >> 4);
+ /* Make sure the gain of the HPF is 1.0. This can still saturate a little under
+ impulse conditions, and it might roll to 32768 and need clipping on sustained peak
+ level signals. However, the scale of such clipping is small, and the error due to
+ any saturation should not markedly affect the downstream processing. */
+ tmp -= (tmp >> 4);
#endif
- ec->rx_1 += -(ec->rx_1>>DC_LOG2BETA) + tmp - ec->rx_2;
+ ec->rx_1 += -(ec->rx_1 >> DC_LOG2BETA) + tmp - ec->rx_2;
+
+ /* hard limit filter to prevent clipping. Note that at this stage
+ rx should be limited to +/- 16383 due to right shift above */
+ tmp1 = ec->rx_1 >> 15;
+ if (tmp1 > 16383)
+ tmp1 = 16383;
+ if (tmp1 < -16383)
+ tmp1 = -16383;
+ rx = tmp1;
+ ec->rx_2 = tmp;
+ }
- /* hard limit filter to prevent clipping. Note that at this stage
- rx should be limited to +/- 16383 due to right shift above */
- tmp1 = ec->rx_1 >> 15;
- if (tmp1 > 16383) tmp1 = 16383;
- if (tmp1 < -16383) tmp1 = -16383;
- rx = tmp1;
- ec->rx_2 = tmp;
- }
+ /* Block average of power in the filter states. Used for
+ adaption power calculation. */
- /* Block average of power in the filter states. Used for
- adaption power calculation. */
+ {
+ int new, old;
+
+ /* efficient "out with the old and in with the new" algorithm so
+ we don't have to recalculate over the whole block of
+ samples. */
+ new = (int)tx *(int)tx;
+ old = (int)ec->fir_state.history[ec->fir_state.curr_pos] *
+ (int)ec->fir_state.history[ec->fir_state.curr_pos];
+ ec->Pstates +=
+ ((new - old) + (1 << ec->log2taps)) >> ec->log2taps;
+ if (ec->Pstates < 0)
+ ec->Pstates = 0;
+ }
- {
- int new, old;
+ /* Calculate short term average levels using simple single pole IIRs */
- /* efficient "out with the old and in with the new" algorithm so
- we don't have to recalculate over the whole block of
- samples. */
- new = (int)tx * (int)tx;
- old = (int)ec->fir_state.history[ec->fir_state.curr_pos] *
- (int)ec->fir_state.history[ec->fir_state.curr_pos];
- ec->Pstates += ((new - old) + (1<<ec->log2taps)) >> ec->log2taps;
- if (ec->Pstates < 0) ec->Pstates = 0;
- }
-
- /* Calculate short term average levels using simple single pole IIRs */
-
- ec->Ltxacc += abs(tx) - ec->Ltx;
- ec->Ltx = (ec->Ltxacc + (1<<4)) >> 5;
- ec->Lrxacc += abs(rx) - ec->Lrx;
- ec->Lrx = (ec->Lrxacc + (1<<4)) >> 5;
-
- /* Foreground filter ---------------------------------------------------*/
-
- ec->fir_state.coeffs = ec->fir_taps16[0];
- echo_value = fir16(&ec->fir_state, tx);
- ec->clean = rx - echo_value;
- ec->Lcleanacc += abs(ec->clean) - ec->Lclean;
- ec->Lclean = (ec->Lcleanacc + (1<<4)) >> 5;
-
- /* Background filter ---------------------------------------------------*/
-
- echo_value = fir16(&ec->fir_state_bg, tx);
- clean_bg = rx - echo_value;
- ec->Lclean_bgacc += abs(clean_bg) - ec->Lclean_bg;
- ec->Lclean_bg = (ec->Lclean_bgacc + (1<<4)) >> 5;
-
- /* Background Filter adaption -----------------------------------------*/
-
- /* Almost always adap bg filter, just simple DT and energy
- detection to minimise adaption in cases of strong double talk.
- However this is not critical for the dual path algorithm.
- */
- ec->factor = 0;
- ec->shift = 0;
- if ((ec->nonupdate_dwell == 0)) {
- int P, logP, shift;
-
- /* Determine:
-
- f = Beta * clean_bg_rx/P ------ (1)
-
- where P is the total power in the filter states.
-
- The Boffins have shown that if we obey (1) we converge
- quickly and avoid instability.
-
- The correct factor f must be in Q30, as this is the fixed
- point format required by the lms_adapt_bg() function,
- therefore the scaled version of (1) is:
-
- (2^30) * f = (2^30) * Beta * clean_bg_rx/P
- factor = (2^30) * Beta * clean_bg_rx/P ----- (2)
-
- We have chosen Beta = 0.25 by experiment, so:
-
- factor = (2^30) * (2^-2) * clean_bg_rx/P
-
- (30 - 2 - log2(P))
- factor = clean_bg_rx 2 ----- (3)
-
- To avoid a divide we approximate log2(P) as top_bit(P),
- which returns the position of the highest non-zero bit in
- P. This approximation introduces an error as large as a
- factor of 2, but the algorithm seems to handle it OK.
-
- Come to think of it a divide may not be a big deal on a
- modern DSP, so its probably worth checking out the cycles
- for a divide versus a top_bit() implementation.
- */
-
- P = MIN_TX_POWER_FOR_ADAPTION + ec->Pstates;
- logP = top_bit(P) + ec->log2taps;
- shift = 30 - 2 - logP;
- ec->shift = shift;
-
- lms_adapt_bg(ec, clean_bg, shift);
- }
-
- /* very simple DTD to make sure we dont try and adapt with strong
- near end speech */
-
- ec->adapt = 0;
- if ((ec->Lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->Lrx > ec->Ltx))
- ec->nonupdate_dwell = DTD_HANGOVER;
- if (ec->nonupdate_dwell)
- ec->nonupdate_dwell--;
+ ec->Ltxacc += abs(tx) - ec->Ltx;
+ ec->Ltx = (ec->Ltxacc + (1 << 4)) >> 5;
+ ec->Lrxacc += abs(rx) - ec->Lrx;
+ ec->Lrx = (ec->Lrxacc + (1 << 4)) >> 5;
- /* Transfer logic ------------------------------------------------------*/
+ /* Foreground filter --------------------------------------------------- */
- /* These conditions are from the dual path paper [1], I messed with
- them a bit to improve performance. */
+ ec->fir_state.coeffs = ec->fir_taps16[0];
+ echo_value = fir16(&ec->fir_state, tx);
+ ec->clean = rx - echo_value;
+ ec->Lcleanacc += abs(ec->clean) - ec->Lclean;
+ ec->Lclean = (ec->Lcleanacc + (1 << 4)) >> 5;
- if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) &&
- (ec->nonupdate_dwell == 0) &&
- (8*ec->Lclean_bg < 7*ec->Lclean) /* (ec->Lclean_bg < 0.875*ec->Lclean) */ &&
- (8*ec->Lclean_bg < ec->Ltx) /* (ec->Lclean_bg < 0.125*ec->Ltx) */ )
- {
- if (ec->cond_met == 6) {
- /* BG filter has had better results for 6 consecutive samples */
- ec->adapt = 1;
- memcpy(ec->fir_taps16[0], ec->fir_taps16[1], ec->taps*sizeof(int16_t));
- }
- else
- ec->cond_met++;
- }
- else
- ec->cond_met = 0;
+ /* Background filter --------------------------------------------------- */
- /* Non-Linear Processing ---------------------------------------------------*/
+ echo_value = fir16(&ec->fir_state_bg, tx);
+ clean_bg = rx - echo_value;
+ ec->Lclean_bgacc += abs(clean_bg) - ec->Lclean_bg;
+ ec->Lclean_bg = (ec->Lclean_bgacc + (1 << 4)) >> 5;
- ec->clean_nlp = ec->clean;
- if (ec->adaption_mode & ECHO_CAN_USE_NLP)
- {
- /* Non-linear processor - a fancy way to say "zap small signals, to avoid
- residual echo due to (uLaw/ALaw) non-linearity in the channel.". */
+ /* Background Filter adaption ----------------------------------------- */
- if ((16*ec->Lclean < ec->Ltx))
- {
- /* Our e/c has improved echo by at least 24 dB (each factor of 2 is 6dB,
- so 2*2*2*2=16 is the same as 6+6+6+6=24dB) */
- if (ec->adaption_mode & ECHO_CAN_USE_CNG)
- {
- ec->cng_level = ec->Lbgn;
-
- /* Very elementary comfort noise generation. Just random
- numbers rolled off very vaguely Hoth-like. DR: This
- noise doesn't sound quite right to me - I suspect there
- are some overlfow issues in the filtering as it's too
- "crackly". TODO: debug this, maybe just play noise at
- high level or look at spectrum.
- */
-
- ec->cng_rndnum = 1664525U*ec->cng_rndnum + 1013904223U;
- ec->cng_filter = ((ec->cng_rndnum & 0xFFFF) - 32768 + 5*ec->cng_filter) >> 3;
- ec->clean_nlp = (ec->cng_filter*ec->cng_level*8) >> 14;
-
- }
- else if (ec->adaption_mode & ECHO_CAN_USE_CLIP)
- {
- /* This sounds much better than CNG */
- if (ec->clean_nlp > ec->Lbgn)
- ec->clean_nlp = ec->Lbgn;
- if (ec->clean_nlp < -ec->Lbgn)
- ec->clean_nlp = -ec->Lbgn;
+ /* Almost always adap bg filter, just simple DT and energy
+ detection to minimise adaption in cases of strong double talk.
+ However this is not critical for the dual path algorithm.
+ */
+ ec->factor = 0;
+ ec->shift = 0;
+ if ((ec->nonupdate_dwell == 0)) {
+ int P, logP, shift;
+
+ /* Determine:
+
+ f = Beta * clean_bg_rx/P ------ (1)
+
+ where P is the total power in the filter states.
+
+ The Boffins have shown that if we obey (1) we converge
+ quickly and avoid instability.
+
+ The correct factor f must be in Q30, as this is the fixed
+ point format required by the lms_adapt_bg() function,
+ therefore the scaled version of (1) is:
+
+ (2^30) * f = (2^30) * Beta * clean_bg_rx/P
+ factor = (2^30) * Beta * clean_bg_rx/P ----- (2)
+
+ We have chosen Beta = 0.25 by experiment, so:
+
+ factor = (2^30) * (2^-2) * clean_bg_rx/P
+
+ (30 - 2 - log2(P))
+ factor = clean_bg_rx 2 ----- (3)
+
+ To avoid a divide we approximate log2(P) as top_bit(P),
+ which returns the position of the highest non-zero bit in
+ P. This approximation introduces an error as large as a
+ factor of 2, but the algorithm seems to handle it OK.
+
+ Come to think of it a divide may not be a big deal on a
+ modern DSP, so its probably worth checking out the cycles
+ for a divide versus a top_bit() implementation.
+ */
+
+ P = MIN_TX_POWER_FOR_ADAPTION + ec->Pstates;
+ logP = top_bit(P) + ec->log2taps;
+ shift = 30 - 2 - logP;
+ ec->shift = shift;
+
+ lms_adapt_bg(ec, clean_bg, shift);
}
- else
- {
- /* just mute the residual, doesn't sound very good, used mainly
- in G168 tests */
- ec->clean_nlp = 0;
- }
- }
- else {
- /* Background noise estimator. I tried a few algorithms
- here without much luck. This very simple one seems to
- work best, we just average the level using a slow (1 sec
- time const) filter if the current level is less than a
- (experimentally derived) constant. This means we dont
- include high level signals like near end speech. When
- combined with CNG or especially CLIP seems to work OK.
- */
- if (ec->Lclean < 40) {
- ec->Lbgn_acc += abs(ec->clean) - ec->Lbgn;
- ec->Lbgn = (ec->Lbgn_acc + (1<<11)) >> 12;
- }
- }
- }
-
- /* Roll around the taps buffer */
- if (ec->curr_pos <= 0)
- ec->curr_pos = ec->taps;
- ec->curr_pos--;
-
- if (ec->adaption_mode & ECHO_CAN_DISABLE)
- ec->clean_nlp = rx;
-
- /* Output scaled back up again to match input scaling */
-
- return (int16_t) ec->clean_nlp << 1;
+
+ /* very simple DTD to make sure we dont try and adapt with strong
+ near end speech */
+
+ ec->adapt = 0;
+ if ((ec->Lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->Lrx > ec->Ltx))
+ ec->nonupdate_dwell = DTD_HANGOVER;
+ if (ec->nonupdate_dwell)
+ ec->nonupdate_dwell--;
+
+ /* Transfer logic ------------------------------------------------------ */
+
+ /* These conditions are from the dual path paper [1], I messed with
+ them a bit to improve performance. */
+
+ if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) &&
+ (ec->nonupdate_dwell == 0) &&
+ (8 * ec->Lclean_bg <
+ 7 * ec->Lclean) /* (ec->Lclean_bg < 0.875*ec->Lclean) */ &&
+ (8 * ec->Lclean_bg <
+ ec->Ltx) /* (ec->Lclean_bg < 0.125*ec->Ltx) */ ) {
+ if (ec->cond_met == 6) {
+ /* BG filter has had better results for 6 consecutive samples */
+ ec->adapt = 1;
+ memcpy(ec->fir_taps16[0], ec->fir_taps16[1],
+ ec->taps * sizeof(int16_t));
+ } else
+ ec->cond_met++;
+ } else
+ ec->cond_met = 0;
+
+ /* Non-Linear Processing --------------------------------------------------- */
+
+ ec->clean_nlp = ec->clean;
+ if (ec->adaption_mode & ECHO_CAN_USE_NLP) {
+ /* Non-linear processor - a fancy way to say "zap small signals, to avoid
+ residual echo due to (uLaw/ALaw) non-linearity in the channel.". */
+
+ if ((16 * ec->Lclean < ec->Ltx)) {
+ /* Our e/c has improved echo by at least 24 dB (each factor of 2 is 6dB,
+ so 2*2*2*2=16 is the same as 6+6+6+6=24dB) */
+ if (ec->adaption_mode & ECHO_CAN_USE_CNG) {
+ ec->cng_level = ec->Lbgn;
+
+ /* Very elementary comfort noise generation. Just random
+ numbers rolled off very vaguely Hoth-like. DR: This
+ noise doesn't sound quite right to me - I suspect there
+ are some overlfow issues in the filtering as it's too
+ "crackly". TODO: debug this, maybe just play noise at
+ high level or look at spectrum.
+ */
+
+ ec->cng_rndnum =
+ 1664525U * ec->cng_rndnum + 1013904223U;
+ ec->cng_filter =
+ ((ec->cng_rndnum & 0xFFFF) - 32768 +
+ 5 * ec->cng_filter) >> 3;
+ ec->clean_nlp =
+ (ec->cng_filter * ec->cng_level * 8) >> 14;
+
+ } else if (ec->adaption_mode & ECHO_CAN_USE_CLIP) {
+ /* This sounds much better than CNG */
+ if (ec->clean_nlp > ec->Lbgn)
+ ec->clean_nlp = ec->Lbgn;
+ if (ec->clean_nlp < -ec->Lbgn)
+ ec->clean_nlp = -ec->Lbgn;
+ } else {
+ /* just mute the residual, doesn't sound very good, used mainly
+ in G168 tests */
+ ec->clean_nlp = 0;
+ }
+ } else {
+ /* Background noise estimator. I tried a few algorithms
+ here without much luck. This very simple one seems to
+ work best, we just average the level using a slow (1 sec
+ time const) filter if the current level is less than a
+ (experimentally derived) constant. This means we dont
+ include high level signals like near end speech. When
+ combined with CNG or especially CLIP seems to work OK.
+ */
+ if (ec->Lclean < 40) {
+ ec->Lbgn_acc += abs(ec->clean) - ec->Lbgn;
+ ec->Lbgn = (ec->Lbgn_acc + (1 << 11)) >> 12;
+ }
+ }
+ }
+
+ /* Roll around the taps buffer */
+ if (ec->curr_pos <= 0)
+ ec->curr_pos = ec->taps;
+ ec->curr_pos--;
+
+ if (ec->adaption_mode & ECHO_CAN_DISABLE)
+ ec->clean_nlp = rx;
+
+ /* Output scaled back up again to match input scaling */
+
+ return (int16_t) ec->clean_nlp << 1;
}
-/*- End of function --------------------------------------------------------*/
+EXPORT_SYMBOL_GPL(oslec_update);
/* This function is seperated from the echo canceller is it is usually called
as part of the tx process. See rx HP (DC blocking) filter above, it's
@@ -608,25 +605,35 @@ int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx)
precision, which noise shapes things, giving very clean DC removal.
*/
-int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx) {
- int tmp, tmp1;
+int16_t oslec_hpf_tx(struct oslec_state * ec, int16_t tx)
+{
+ int tmp, tmp1;
- if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) {
- tmp = tx << 15;
+ if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) {
+ tmp = tx << 15;
#if 1
- /* Make sure the gain of the HPF is 1.0. The first can still saturate a little under
- impulse conditions, and it might roll to 32768 and need clipping on sustained peak
- level signals. However, the scale of such clipping is small, and the error due to
- any saturation should not markedly affect the downstream processing. */
- tmp -= (tmp >> 4);
+ /* Make sure the gain of the HPF is 1.0. The first can still saturate a little under
+ impulse conditions, and it might roll to 32768 and need clipping on sustained peak
+ level signals. However, the scale of such clipping is small, and the error due to
+ any saturation should not markedly affect the downstream processing. */
+ tmp -= (tmp >> 4);
#endif
- ec->tx_1 += -(ec->tx_1>>DC_LOG2BETA) + tmp - ec->tx_2;
- tmp1 = ec->tx_1 >> 15;
- if (tmp1 > 32767) tmp1 = 32767;
- if (tmp1 < -32767) tmp1 = -32767;
- tx = tmp1;
- ec->tx_2 = tmp;
- }
-
- return tx;
+ ec->tx_1 += -(ec->tx_1 >> DC_LOG2BETA) + tmp - ec->tx_2;
+ tmp1 = ec->tx_1 >> 15;
+ if (tmp1 > 32767)
+ tmp1 = 32767;
+ if (tmp1 < -32767)
+ tmp1 = -32767;
+ tx = tmp1;
+ ec->tx_2 = tmp;
+ }
+
+ return tx;
}
+
+EXPORT_SYMBOL_GPL(oslec_hpf_tx);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Rowe");
+MODULE_DESCRIPTION("Open Source Line Echo Canceller");
+MODULE_VERSION("0.3.0");
diff --git a/drivers/staging/echo/echo.h b/drivers/staging/echo/echo.h
index 7a91b4390f3..9fb9543c4f1 100644
--- a/drivers/staging/echo/echo.h
+++ b/drivers/staging/echo/echo.h
@@ -118,23 +118,14 @@ a minor burden.
*/
#include "fir.h"
-
-/* Mask bits for the adaption mode */
-#define ECHO_CAN_USE_ADAPTION 0x01
-#define ECHO_CAN_USE_NLP 0x02
-#define ECHO_CAN_USE_CNG 0x04
-#define ECHO_CAN_USE_CLIP 0x08
-#define ECHO_CAN_USE_TX_HPF 0x10
-#define ECHO_CAN_USE_RX_HPF 0x20
-#define ECHO_CAN_DISABLE 0x40
+#include "oslec.h"
/*!
G.168 echo canceller descriptor. This defines the working state for a line
echo canceller.
*/
-typedef struct
-{
- int16_t tx,rx;
+struct oslec_state {
+ int16_t tx, rx;
int16_t clean;
int16_t clean_nlp;
@@ -176,45 +167,6 @@ typedef struct
/* snapshot sample of coeffs used for development */
int16_t *snapshot;
-} echo_can_state_t;
-
-/*! Create a voice echo canceller context.
- \param len The length of the canceller, in samples.
- \return The new canceller context, or NULL if the canceller could not be created.
-*/
-echo_can_state_t *echo_can_create(int len, int adaption_mode);
-
-/*! Free a voice echo canceller context.
- \param ec The echo canceller context.
-*/
-void echo_can_free(echo_can_state_t *ec);
-
-/*! Flush (reinitialise) a voice echo canceller context.
- \param ec The echo canceller context.
-*/
-void echo_can_flush(echo_can_state_t *ec);
-
-/*! Set the adaption mode of a voice echo canceller context.
- \param ec The echo canceller context.
- \param adapt The mode.
-*/
-void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode);
-
-void echo_can_snapshot(echo_can_state_t *ec);
-
-/*! Process a sample through a voice echo canceller.
- \param ec The echo canceller context.
- \param tx The transmitted audio sample.
- \param rx The received audio sample.
- \return The clean (echo cancelled) received sample.
-*/
-int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx);
-
-/*! Process to high pass filter the tx signal.
- \param ec The echo canceller context.
- \param tx The transmitted auio sample.
- \return The HP filtered transmit sample, send this to your D/A.
-*/
-int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx);
+};
-#endif /* __ECHO_H */
+#endif /* __ECHO_H */
diff --git a/drivers/staging/echo/fir.h b/drivers/staging/echo/fir.h
index e1bfc499488..5645cb1b2f9 100644
--- a/drivers/staging/echo/fir.h
+++ b/drivers/staging/echo/fir.h
@@ -72,8 +72,7 @@
16 bit integer FIR descriptor. This defines the working state for a single
instance of an FIR filter using 16 bit integer coefficients.
*/
-typedef struct
-{
+typedef struct {
int taps;
int curr_pos;
const int16_t *coeffs;
@@ -85,8 +84,7 @@ typedef struct
instance of an FIR filter using 32 bit integer coefficients, and filtering
16 bit integer data.
*/
-typedef struct
-{
+typedef struct {
int taps;
int curr_pos;
const int32_t *coeffs;
@@ -97,273 +95,201 @@ typedef struct
Floating point FIR descriptor. This defines the working state for a single
instance of an FIR filter using floating point coefficients and data.
*/
-typedef struct
-{
+typedef struct {
int taps;
int curr_pos;
const float *coeffs;
float *history;
} fir_float_state_t;
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-static __inline__ const int16_t *fir16_create(fir16_state_t *fir,
- const int16_t *coeffs,
- int taps)
+static __inline__ const int16_t *fir16_create(fir16_state_t * fir,
+ const int16_t * coeffs, int taps)
{
fir->taps = taps;
fir->curr_pos = taps - 1;
fir->coeffs = coeffs;
-#if defined(USE_MMX) || defined(USE_SSE2) || defined(__BLACKFIN_ASM__)
- if ((fir->history = malloc(2*taps*sizeof(int16_t))))
- memset(fir->history, 0, 2*taps*sizeof(int16_t));
+#if defined(USE_MMX) || defined(USE_SSE2) || defined(__bfin__)
+ fir->history = kcalloc(2 * taps, sizeof(int16_t), GFP_KERNEL);
#else
- if ((fir->history = (int16_t *) malloc(taps*sizeof(int16_t))))
- memset(fir->history, 0, taps*sizeof(int16_t));
+ fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
#endif
return fir->history;
}
-/*- End of function --------------------------------------------------------*/
-static __inline__ void fir16_flush(fir16_state_t *fir)
+static __inline__ void fir16_flush(fir16_state_t * fir)
{
-#if defined(USE_MMX) || defined(USE_SSE2) || defined(__BLACKFIN_ASM__)
- memset(fir->history, 0, 2*fir->taps*sizeof(int16_t));
+#if defined(USE_MMX) || defined(USE_SSE2) || defined(__bfin__)
+ memset(fir->history, 0, 2 * fir->taps * sizeof(int16_t));
#else
- memset(fir->history, 0, fir->taps*sizeof(int16_t));
+ memset(fir->history, 0, fir->taps * sizeof(int16_t));
#endif
}
-/*- End of function --------------------------------------------------------*/
-static __inline__ void fir16_free(fir16_state_t *fir)
+static __inline__ void fir16_free(fir16_state_t * fir)
{
- free(fir->history);
+ kfree(fir->history);
}
-/*- End of function --------------------------------------------------------*/
-#ifdef __BLACKFIN_ASM__
+#ifdef __bfin__
static inline int32_t dot_asm(short *x, short *y, int len)
{
- int dot;
-
- len--;
-
- __asm__
- (
- "I0 = %1;\n\t"
- "I1 = %2;\n\t"
- "A0 = 0;\n\t"
- "R0.L = W[I0++] || R1.L = W[I1++];\n\t"
- "LOOP dot%= LC0 = %3;\n\t"
- "LOOP_BEGIN dot%=;\n\t"
- "A0 += R0.L * R1.L (IS) || R0.L = W[I0++] || R1.L = W[I1++];\n\t"
- "LOOP_END dot%=;\n\t"
- "A0 += R0.L*R1.L (IS);\n\t"
- "R0 = A0;\n\t"
- "%0 = R0;\n\t"
- : "=&d" (dot)
- : "a" (x), "a" (y), "a" (len)
- : "I0", "I1", "A1", "A0", "R0", "R1"
- );
-
- return dot;
+ int dot;
+
+ len--;
+
+ __asm__("I0 = %1;\n\t"
+ "I1 = %2;\n\t"
+ "A0 = 0;\n\t"
+ "R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+ "LOOP dot%= LC0 = %3;\n\t"
+ "LOOP_BEGIN dot%=;\n\t"
+ "A0 += R0.L * R1.L (IS) || R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+ "LOOP_END dot%=;\n\t"
+ "A0 += R0.L*R1.L (IS);\n\t"
+ "R0 = A0;\n\t"
+ "%0 = R0;\n\t"
+ :"=&d"(dot)
+ :"a"(x), "a"(y), "a"(len)
+ :"I0", "I1", "A1", "A0", "R0", "R1"
+ );
+
+ return dot;
}
#endif
-/*- End of function --------------------------------------------------------*/
-static __inline__ int16_t fir16(fir16_state_t *fir, int16_t sample)
+static __inline__ int16_t fir16(fir16_state_t * fir, int16_t sample)
{
- int32_t y;
+ int32_t y;
#if defined(USE_MMX)
- int i;
- mmx_t *mmx_coeffs;
- mmx_t *mmx_hist;
-
- fir->history[fir->curr_pos] = sample;
- fir->history[fir->curr_pos + fir->taps] = sample;
-
- mmx_coeffs = (mmx_t *) fir->coeffs;
- mmx_hist = (mmx_t *) &fir->history[fir->curr_pos];
- i = fir->taps;
- pxor_r2r(mm4, mm4);
- /* 8 samples per iteration, so the filter must be a multiple of 8 long. */
- while (i > 0)
- {
- movq_m2r(mmx_coeffs[0], mm0);
- movq_m2r(mmx_coeffs[1], mm2);
- movq_m2r(mmx_hist[0], mm1);
- movq_m2r(mmx_hist[1], mm3);
- mmx_coeffs += 2;
- mmx_hist += 2;
- pmaddwd_r2r(mm1, mm0);
- pmaddwd_r2r(mm3, mm2);
- paddd_r2r(mm0, mm4);
- paddd_r2r(mm2, mm4);
- i -= 8;
- }
- movq_r2r(mm4, mm0);
- psrlq_i2r(32, mm0);
- paddd_r2r(mm0, mm4);
- movd_r2m(mm4, y);
- emms();
+ int i;
+ mmx_t *mmx_coeffs;
+ mmx_t *mmx_hist;
+
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+
+ mmx_coeffs = (mmx_t *) fir->coeffs;
+ mmx_hist = (mmx_t *) & fir->history[fir->curr_pos];
+ i = fir->taps;
+ pxor_r2r(mm4, mm4);
+ /* 8 samples per iteration, so the filter must be a multiple of 8 long. */
+ while (i > 0) {
+ movq_m2r(mmx_coeffs[0], mm0);
+ movq_m2r(mmx_coeffs[1], mm2);
+ movq_m2r(mmx_hist[0], mm1);
+ movq_m2r(mmx_hist[1], mm3);
+ mmx_coeffs += 2;
+ mmx_hist += 2;
+ pmaddwd_r2r(mm1, mm0);
+ pmaddwd_r2r(mm3, mm2);
+ paddd_r2r(mm0, mm4);
+ paddd_r2r(mm2, mm4);
+ i -= 8;
+ }
+ movq_r2r(mm4, mm0);
+ psrlq_i2r(32, mm0);
+ paddd_r2r(mm0, mm4);
+ movd_r2m(mm4, y);
+ emms();
#elif defined(USE_SSE2)
- int i;
- xmm_t *xmm_coeffs;
- xmm_t *xmm_hist;
-
- fir->history[fir->curr_pos] = sample;
- fir->history[fir->curr_pos + fir->taps] = sample;
-
- xmm_coeffs = (xmm_t *) fir->coeffs;
- xmm_hist = (xmm_t *) &fir->history[fir->curr_pos];
- i = fir->taps;
- pxor_r2r(xmm4, xmm4);
- /* 16 samples per iteration, so the filter must be a multiple of 16 long. */
- while (i > 0)
- {
- movdqu_m2r(xmm_coeffs[0], xmm0);
- movdqu_m2r(xmm_coeffs[1], xmm2);
- movdqu_m2r(xmm_hist[0], xmm1);
- movdqu_m2r(xmm_hist[1], xmm3);
- xmm_coeffs += 2;
- xmm_hist += 2;
- pmaddwd_r2r(xmm1, xmm0);
- pmaddwd_r2r(xmm3, xmm2);
- paddd_r2r(xmm0, xmm4);
- paddd_r2r(xmm2, xmm4);
- i -= 16;
- }
- movdqa_r2r(xmm4, xmm0);
- psrldq_i2r(8, xmm0);
- paddd_r2r(xmm0, xmm4);
- movdqa_r2r(xmm4, xmm0);
- psrldq_i2r(4, xmm0);
- paddd_r2r(xmm0, xmm4);
- movd_r2m(xmm4, y);
-#elif defined(__BLACKFIN_ASM__)
- fir->history[fir->curr_pos] = sample;
- fir->history[fir->curr_pos + fir->taps] = sample;
- y = dot_asm((int16_t*)fir->coeffs, &fir->history[fir->curr_pos], fir->taps);
+ int i;
+ xmm_t *xmm_coeffs;
+ xmm_t *xmm_hist;
+
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+
+ xmm_coeffs = (xmm_t *) fir->coeffs;
+ xmm_hist = (xmm_t *) & fir->history[fir->curr_pos];
+ i = fir->taps;
+ pxor_r2r(xmm4, xmm4);
+ /* 16 samples per iteration, so the filter must be a multiple of 16 long. */
+ while (i > 0) {
+ movdqu_m2r(xmm_coeffs[0], xmm0);
+ movdqu_m2r(xmm_coeffs[1], xmm2);
+ movdqu_m2r(xmm_hist[0], xmm1);
+ movdqu_m2r(xmm_hist[1], xmm3);
+ xmm_coeffs += 2;
+ xmm_hist += 2;
+ pmaddwd_r2r(xmm1, xmm0);
+ pmaddwd_r2r(xmm3, xmm2);
+ paddd_r2r(xmm0, xmm4);
+ paddd_r2r(xmm2, xmm4);
+ i -= 16;
+ }
+ movdqa_r2r(xmm4, xmm0);
+ psrldq_i2r(8, xmm0);
+ paddd_r2r(xmm0, xmm4);
+ movdqa_r2r(xmm4, xmm0);
+ psrldq_i2r(4, xmm0);
+ paddd_r2r(xmm0, xmm4);
+ movd_r2m(xmm4, y);
+#elif defined(__bfin__)
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+ y = dot_asm((int16_t *) fir->coeffs, &fir->history[fir->curr_pos],
+ fir->taps);
#else
- int i;
- int offset1;
- int offset2;
-
- fir->history[fir->curr_pos] = sample;
-
- offset2 = fir->curr_pos;
- offset1 = fir->taps - offset2;
- y = 0;
- for (i = fir->taps - 1; i >= offset1; i--)
- y += fir->coeffs[i]*fir->history[i - offset1];
- for ( ; i >= 0; i--)
- y += fir->coeffs[i]*fir->history[i + offset2];
+ int i;
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i] * fir->history[i - offset1];
+ for (; i >= 0; i--)
+ y += fir->coeffs[i] * fir->history[i + offset2];
#endif
- if (fir->curr_pos <= 0)
- fir->curr_pos = fir->taps;
- fir->curr_pos--;
- return (int16_t) (y >> 15);
-}
-/*- End of function --------------------------------------------------------*/
-
-static __inline__ const int16_t *fir32_create(fir32_state_t *fir,
- const int32_t *coeffs,
- int taps)
-{
- fir->taps = taps;
- fir->curr_pos = taps - 1;
- fir->coeffs = coeffs;
- fir->history = (int16_t *) malloc(taps*sizeof(int16_t));
- if (fir->history)
- memset(fir->history, '\0', taps*sizeof(int16_t));
- return fir->history;
-}
-/*- End of function --------------------------------------------------------*/
-
-static __inline__ void fir32_flush(fir32_state_t *fir)
-{
- memset(fir->history, 0, fir->taps*sizeof(int16_t));
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) (y >> 15);
}
-/*- End of function --------------------------------------------------------*/
-static __inline__ void fir32_free(fir32_state_t *fir)
+static __inline__ const int16_t *fir32_create(fir32_state_t * fir,
+ const int32_t * coeffs, int taps)
{
- free(fir->history);
-}
-/*- End of function --------------------------------------------------------*/
-
-static __inline__ int16_t fir32(fir32_state_t *fir, int16_t sample)
-{
- int i;
- int32_t y;
- int offset1;
- int offset2;
-
- fir->history[fir->curr_pos] = sample;
- offset2 = fir->curr_pos;
- offset1 = fir->taps - offset2;
- y = 0;
- for (i = fir->taps - 1; i >= offset1; i--)
- y += fir->coeffs[i]*fir->history[i - offset1];
- for ( ; i >= 0; i--)
- y += fir->coeffs[i]*fir->history[i + offset2];
- if (fir->curr_pos <= 0)
- fir->curr_pos = fir->taps;
- fir->curr_pos--;
- return (int16_t) (y >> 15);
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+ fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
+ return fir->history;
}
-/*- End of function --------------------------------------------------------*/
-#ifndef __KERNEL__
-static __inline__ const float *fir_float_create(fir_float_state_t *fir,
- const float *coeffs,
- int taps)
+static __inline__ void fir32_flush(fir32_state_t * fir)
{
- fir->taps = taps;
- fir->curr_pos = taps - 1;
- fir->coeffs = coeffs;
- fir->history = (float *) malloc(taps*sizeof(float));
- if (fir->history)
- memset(fir->history, '\0', taps*sizeof(float));
- return fir->history;
+ memset(fir->history, 0, fir->taps * sizeof(int16_t));
}
-/*- End of function --------------------------------------------------------*/
-static __inline__ void fir_float_free(fir_float_state_t *fir)
+static __inline__ void fir32_free(fir32_state_t * fir)
{
- free(fir->history);
+ kfree(fir->history);
}
-/*- End of function --------------------------------------------------------*/
-static __inline__ int16_t fir_float(fir_float_state_t *fir, int16_t sample)
+static __inline__ int16_t fir32(fir32_state_t * fir, int16_t sample)
{
- int i;
- float y;
- int offset1;
- int offset2;
-
- fir->history[fir->curr_pos] = sample;
-
- offset2 = fir->curr_pos;
- offset1 = fir->taps - offset2;
- y = 0;
- for (i = fir->taps - 1; i >= offset1; i--)
- y += fir->coeffs[i]*fir->history[i - offset1];
- for ( ; i >= 0; i--)
- y += fir->coeffs[i]*fir->history[i + offset2];
- if (fir->curr_pos <= 0)
- fir->curr_pos = fir->taps;
- fir->curr_pos--;
- return (int16_t) y;
+ int i;
+ int32_t y;
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i] * fir->history[i - offset1];
+ for (; i >= 0; i--)
+ y += fir->coeffs[i] * fir->history[i + offset2];
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) (y >> 15);
}
-/*- End of function --------------------------------------------------------*/
-#endif
-
-#ifdef __cplusplus
-}
-#endif
#endif
/*- End of file ------------------------------------------------------------*/
diff --git a/drivers/staging/echo/mmx.h b/drivers/staging/echo/mmx.h
index b5a3964865b..35412efe61c 100644
--- a/drivers/staging/echo/mmx.h
+++ b/drivers/staging/echo/mmx.h
@@ -27,24 +27,23 @@
* values by ULL, lest they be truncated by the compiler)
*/
-typedef union {
- long long q; /* Quadword (64-bit) value */
- unsigned long long uq; /* Unsigned Quadword */
- int d[2]; /* 2 Doubleword (32-bit) values */
- unsigned int ud[2]; /* 2 Unsigned Doubleword */
- short w[4]; /* 4 Word (16-bit) values */
- unsigned short uw[4]; /* 4 Unsigned Word */
- char b[8]; /* 8 Byte (8-bit) values */
- unsigned char ub[8]; /* 8 Unsigned Byte */
- float s[2]; /* Single-precision (32-bit) value */
-} mmx_t; /* On an 8-byte (64-bit) boundary */
+typedef union {
+ long long q; /* Quadword (64-bit) value */
+ unsigned long long uq; /* Unsigned Quadword */
+ int d[2]; /* 2 Doubleword (32-bit) values */
+ unsigned int ud[2]; /* 2 Unsigned Doubleword */
+ short w[4]; /* 4 Word (16-bit) values */
+ unsigned short uw[4]; /* 4 Unsigned Word */
+ char b[8]; /* 8 Byte (8-bit) values */
+ unsigned char ub[8]; /* 8 Unsigned Byte */
+ float s[2]; /* Single-precision (32-bit) value */
+} mmx_t; /* On an 8-byte (64-bit) boundary */
/* SSE registers */
typedef union {
char b[16];
} xmm_t;
-
#define mmx_i2r(op,imm,reg) \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
@@ -63,7 +62,6 @@ typedef union {
#define mmx_r2r(op,regs,regd) \
__asm__ __volatile__ (#op " %" #regs ", %" #regd)
-
#define emms() __asm__ __volatile__ ("emms")
#define movd_m2r(var,reg) mmx_m2r (movd, var, reg)
@@ -192,16 +190,13 @@ typedef union {
#define pxor_m2r(var,reg) mmx_m2r (pxor, var, reg)
#define pxor_r2r(regs,regd) mmx_r2r (pxor, regs, regd)
-
/* 3DNOW extensions */
#define pavgusb_m2r(var,reg) mmx_m2r (pavgusb, var, reg)
#define pavgusb_r2r(regs,regd) mmx_r2r (pavgusb, regs, regd)
-
/* AMD MMX extensions - also available in intel SSE */
-
#define mmx_m2ri(op,mem,reg,imm) \
__asm__ __volatile__ (#op " %1, %0, %%" #reg \
: /* nothing */ \
@@ -216,7 +211,6 @@ typedef union {
: /* nothing */ \
: "m" (mem))
-
#define maskmovq(regs,maskreg) mmx_r2ri (maskmovq, regs, maskreg)
#define movntq_r2m(mmreg,var) mmx_r2m (movntq, mmreg, var)
@@ -284,5 +278,4 @@ typedef union {
#define punpcklqdq_r2r(regs,regd) mmx_r2r (punpcklqdq, regs, regd)
#define punpckhqdq_r2r(regs,regd) mmx_r2r (punpckhqdq, regs, regd)
-
#endif /* AVCODEC_I386MMX_H */
diff --git a/drivers/staging/echo/oslec.h b/drivers/staging/echo/oslec.h
new file mode 100644
index 00000000000..bad852328a2
--- /dev/null
+++ b/drivers/staging/echo/oslec.h
@@ -0,0 +1,86 @@
+/*
+ * OSLEC - A line echo canceller. This code is being developed
+ * against and partially complies with G168. Using code from SpanDSP
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ * and David Rowe <david_at_rowetel_dot_com>
+ *
+ * Copyright (C) 2001 Steve Underwood and 2007-2008 David Rowe
+ *
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __OSLEC_H
+#define __OSLEC_H
+
+/* TODO: document interface */
+
+/* Mask bits for the adaption mode */
+#define ECHO_CAN_USE_ADAPTION 0x01
+#define ECHO_CAN_USE_NLP 0x02
+#define ECHO_CAN_USE_CNG 0x04
+#define ECHO_CAN_USE_CLIP 0x08
+#define ECHO_CAN_USE_TX_HPF 0x10
+#define ECHO_CAN_USE_RX_HPF 0x20
+#define ECHO_CAN_DISABLE 0x40
+
+/*!
+ G.168 echo canceller descriptor. This defines the working state for a line
+ echo canceller.
+*/
+struct oslec_state;
+
+/*! Create a voice echo canceller context.
+ \param len The length of the canceller, in samples.
+ \return The new canceller context, or NULL if the canceller could not be created.
+*/
+struct oslec_state *oslec_create(int len, int adaption_mode);
+
+/*! Free a voice echo canceller context.
+ \param ec The echo canceller context.
+*/
+void oslec_free(struct oslec_state *ec);
+
+/*! Flush (reinitialise) a voice echo canceller context.
+ \param ec The echo canceller context.
+*/
+void oslec_flush(struct oslec_state *ec);
+
+/*! Set the adaption mode of a voice echo canceller context.
+ \param ec The echo canceller context.
+ \param adapt The mode.
+*/
+void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode);
+
+void oslec_snapshot(struct oslec_state *ec);
+
+/*! Process a sample through a voice echo canceller.
+ \param ec The echo canceller context.
+ \param tx The transmitted audio sample.
+ \param rx The received audio sample.
+ \return The clean (echo cancelled) received sample.
+*/
+int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx);
+
+/*! Process to high pass filter the tx signal.
+ \param ec The echo canceller context.
+ \param tx The transmitted auio sample.
+ \return The HP filtered transmit sample, send this to your D/A.
+*/
+int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx);
+
+#endif /* __OSLEC_H */
diff --git a/drivers/staging/et131x/et1310_phy.c b/drivers/staging/et131x/et1310_phy.c
index 6c4fa54419e..9dd6dfd9a03 100644
--- a/drivers/staging/et131x/et1310_phy.c
+++ b/drivers/staging/et131x/et1310_phy.c
@@ -84,7 +84,6 @@
#include <linux/if_arp.h>
#include <linux/ioport.h>
#include <linux/random.h>
-#include <linux/delay.h>
#include "et1310_phy.h"
#include "et1310_pm.h"
@@ -95,7 +94,6 @@
#include "et131x_initpci.h"
#include "et1310_address_map.h"
-#include "et1310_jagcore.h"
#include "et1310_tx.h"
#include "et1310_rx.h"
#include "et1310_mac.h"
diff --git a/drivers/staging/et131x/et131x_debug.c b/drivers/staging/et131x/et131x_debug.c
index 9ee5bce92c2..d1dd46e0a9c 100644
--- a/drivers/staging/et131x/et131x_debug.c
+++ b/drivers/staging/et131x/et131x_debug.c
@@ -97,7 +97,6 @@
#include "et131x_isr.h"
#include "et1310_address_map.h"
-#include "et1310_jagcore.h"
#include "et1310_tx.h"
#include "et1310_rx.h"
#include "et1310_mac.h"
diff --git a/drivers/staging/et131x/et131x_initpci.c b/drivers/staging/et131x/et131x_initpci.c
index 4c6f171f5b7..a18c499d0ae 100644
--- a/drivers/staging/et131x/et131x_initpci.c
+++ b/drivers/staging/et131x/et131x_initpci.c
@@ -97,7 +97,6 @@
#include "et131x_isr.h"
#include "et1310_address_map.h"
-#include "et1310_jagcore.h"
#include "et1310_tx.h"
#include "et1310_rx.h"
#include "et1310_mac.h"
diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/go7007/Kconfig
index 57a121c338c..593fdb767aa 100644
--- a/drivers/staging/go7007/Kconfig
+++ b/drivers/staging/go7007/Kconfig
@@ -1,10 +1,12 @@
config VIDEO_GO7007
tristate "Go 7007 support"
depends on VIDEO_DEV && PCI && I2C && INPUT
+ depends on SND
select VIDEOBUF_DMA_SG
select VIDEO_IR
select VIDEO_TUNER
select VIDEO_TVEEPROM
+ select SND_PCM
select CRC32
default N
---help---
diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c
index 81ae4b0fa89..e4ead96679c 100644
--- a/drivers/staging/go7007/go7007-driver.c
+++ b/drivers/staging/go7007/go7007-driver.c
@@ -16,7 +16,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
diff --git a/drivers/staging/go7007/go7007-fw.c b/drivers/staging/go7007/go7007-fw.c
index c2aea1020b0..a0e17b0e0ce 100644
--- a/drivers/staging/go7007/go7007-fw.c
+++ b/drivers/staging/go7007/go7007-fw.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/device.h>
diff --git a/drivers/staging/go7007/go7007-i2c.c b/drivers/staging/go7007/go7007-i2c.c
index 10baae3dade..cd55b76eabc 100644
--- a/drivers/staging/go7007/go7007-i2c.c
+++ b/drivers/staging/go7007/go7007-i2c.c
@@ -15,7 +15,6 @@
* Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/go7007/go7007-usb.c
index d4ed6d2b715..3f5ee3424e7 100644
--- a/drivers/staging/go7007/go7007-usb.c
+++ b/drivers/staging/go7007/go7007-usb.c
@@ -16,7 +16,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/wait.h>
diff --git a/drivers/staging/go7007/snd-go7007.c b/drivers/staging/go7007/snd-go7007.c
index 382740c405f..a7de401f61a 100644
--- a/drivers/staging/go7007/snd-go7007.c
+++ b/drivers/staging/go7007/snd-go7007.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/spinlock.h>
diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c
index f5f11e927af..2f9efca0460 100644
--- a/drivers/staging/go7007/wis-ov7640.c
+++ b/drivers/staging/go7007/wis-ov7640.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c
index c1aff1b923a..11689723945 100644
--- a/drivers/staging/go7007/wis-saa7113.c
+++ b/drivers/staging/go7007/wis-saa7113.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/ioctl.h>
diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c
index 5c94c883b31..59417a7174d 100644
--- a/drivers/staging/go7007/wis-saa7115.c
+++ b/drivers/staging/go7007/wis-saa7115.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/ioctl.h>
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c
index 5997fb47945..5a91ee409a7 100644
--- a/drivers/staging/go7007/wis-sony-tuner.c
+++ b/drivers/staging/go7007/wis-sony-tuner.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/tuner.h>
diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c
index 27fe4d0d4ed..57b8f2b1caa 100644
--- a/drivers/staging/go7007/wis-tw2804.c
+++ b/drivers/staging/go7007/wis-tw2804.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/ioctl.h>
diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c
index d8e41968022..40627b282cb 100644
--- a/drivers/staging/go7007/wis-tw9903.c
+++ b/drivers/staging/go7007/wis-tw9903.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/ioctl.h>
diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c
index a0894e3cb8c..555645c0cc1 100644
--- a/drivers/staging/go7007/wis-uda1342.c
+++ b/drivers/staging/go7007/wis-uda1342.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/tvaudio.h>
diff --git a/drivers/staging/me4000/me4000.c b/drivers/staging/me4000/me4000.c
index 862dd7ffb5c..0b33773bb4f 100644
--- a/drivers/staging/me4000/me4000.c
+++ b/drivers/staging/me4000/me4000.c
@@ -25,24 +25,21 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/delay.h>
-#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/unistd.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
-
+#include <linux/types.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
+#include <linux/slab.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
-#include <linux/types.h>
-
-#include <linux/slab.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
/* Include-File for the Meilhaus ME-4000 I/O board */
#include "me4000.h"
@@ -57,14 +54,14 @@ MODULE_SUPPORTED_DEVICE("Meilhaus ME-4000 Multi I/O boards");
MODULE_LICENSE("GPL");
/* Board specific data are kept in a global list */
-LIST_HEAD(me4000_board_info_list);
+static LIST_HEAD(me4000_board_info_list);
/* Major Device Numbers. 0 means to get it automatically from the System */
-static int me4000_ao_major_driver_no = 0;
-static int me4000_ai_major_driver_no = 0;
-static int me4000_dio_major_driver_no = 0;
-static int me4000_cnt_major_driver_no = 0;
-static int me4000_ext_int_major_driver_no = 0;
+static int me4000_ao_major_driver_no;
+static int me4000_ai_major_driver_no;
+static int me4000_dio_major_driver_no;
+static int me4000_cnt_major_driver_no;
+static int me4000_ext_int_major_driver_no;
/* Let the user specify a custom major driver number */
module_param(me4000_ao_major_driver_no, int, 0);
@@ -88,36 +85,22 @@ MODULE_PARM_DESC(me4000_ext_int_major_driver_no,
"Major driver number for external interrupt (default 0)");
/*-----------------------------------------------------------------------------
- Module stuff
- ---------------------------------------------------------------------------*/
-int init_module(void);
-void cleanup_module(void);
-
-/*-----------------------------------------------------------------------------
Board detection and initialization
---------------------------------------------------------------------------*/
static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id);
-static int me4000_xilinx_download(me4000_info_t *);
-static int me4000_reset_board(me4000_info_t *);
+static int me4000_xilinx_download(struct me4000_info *);
+static int me4000_reset_board(struct me4000_info *);
static void clear_board_info_list(void);
-static int get_registers(struct pci_dev *dev, me4000_info_t * info);
-static int init_board_info(struct pci_dev *dev, me4000_info_t * board_info);
-static int alloc_ao_contexts(me4000_info_t * info);
-static void release_ao_contexts(me4000_info_t * board_info);
-static int alloc_ai_context(me4000_info_t * info);
-static int alloc_dio_context(me4000_info_t * info);
-static int alloc_cnt_context(me4000_info_t * info);
-static int alloc_ext_int_context(me4000_info_t * info);
-
+static void release_ao_contexts(struct me4000_info *board_info);
/*-----------------------------------------------------------------------------
Stuff used by all device parts
---------------------------------------------------------------------------*/
static int me4000_open(struct inode *, struct file *);
static int me4000_release(struct inode *, struct file *);
-static int me4000_get_user_info(me4000_user_info_t *,
- me4000_info_t * board_info);
+static int me4000_get_user_info(struct me4000_user_info *,
+ struct me4000_info *board_info);
static int me4000_read_procmem(char *, char **, off_t, int, int *, void *);
/*-----------------------------------------------------------------------------
@@ -140,40 +123,42 @@ static int me4000_ao_ioctl_cont(struct inode *, struct file *, unsigned int,
static unsigned int me4000_ao_poll_cont(struct file *, poll_table *);
static int me4000_ao_fsync_cont(struct file *, struct dentry *, int);
-static int me4000_ao_start(unsigned long *, me4000_ao_context_t *);
-static int me4000_ao_stop(me4000_ao_context_t *);
-static int me4000_ao_immediate_stop(me4000_ao_context_t *);
-static int me4000_ao_timer_set_divisor(u32 *, me4000_ao_context_t *);
-static int me4000_ao_preload(me4000_ao_context_t *);
-static int me4000_ao_preload_update(me4000_ao_context_t *);
-static int me4000_ao_ex_trig_set_edge(int *, me4000_ao_context_t *);
-static int me4000_ao_ex_trig_enable(me4000_ao_context_t *);
-static int me4000_ao_ex_trig_disable(me4000_ao_context_t *);
-static int me4000_ao_prepare(me4000_ao_context_t * ao_info);
-static int me4000_ao_reset(me4000_ao_context_t * ao_info);
-static int me4000_ao_enable_do(me4000_ao_context_t *);
-static int me4000_ao_disable_do(me4000_ao_context_t *);
-static int me4000_ao_fsm_state(int *, me4000_ao_context_t *);
-
-static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context);
-static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context);
-static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context);
-static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * channels,
- me4000_ao_context_t * ao_context);
-
-static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context);
-static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context);
-static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context);
+static int me4000_ao_start(unsigned long *, struct me4000_ao_context *);
+static int me4000_ao_stop(struct me4000_ao_context *);
+static int me4000_ao_immediate_stop(struct me4000_ao_context *);
+static int me4000_ao_timer_set_divisor(u32 *, struct me4000_ao_context *);
+static int me4000_ao_preload(struct me4000_ao_context *);
+static int me4000_ao_preload_update(struct me4000_ao_context *);
+static int me4000_ao_ex_trig_set_edge(int *, struct me4000_ao_context *);
+static int me4000_ao_ex_trig_enable(struct me4000_ao_context *);
+static int me4000_ao_ex_trig_disable(struct me4000_ao_context *);
+static int me4000_ao_prepare(struct me4000_ao_context *ao_info);
+static int me4000_ao_reset(struct me4000_ao_context *ao_info);
+static int me4000_ao_enable_do(struct me4000_ao_context *);
+static int me4000_ao_disable_do(struct me4000_ao_context *);
+static int me4000_ao_fsm_state(int *, struct me4000_ao_context *);
+
+static int me4000_ao_simultaneous_ex_trig(struct me4000_ao_context *ao_context);
+static int me4000_ao_simultaneous_sw(struct me4000_ao_context *ao_context);
+static int me4000_ao_simultaneous_disable(struct me4000_ao_context *ao_context);
+static int me4000_ao_simultaneous_update(
+ struct me4000_ao_channel_list *channels,
+ struct me4000_ao_context *ao_context);
+
+static int me4000_ao_synchronous_ex_trig(struct me4000_ao_context *ao_context);
+static int me4000_ao_synchronous_sw(struct me4000_ao_context *ao_context);
+static int me4000_ao_synchronous_disable(struct me4000_ao_context *ao_context);
static int me4000_ao_ex_trig_timeout(unsigned long *arg,
- me4000_ao_context_t * ao_context);
+ struct me4000_ao_context *ao_context);
static int me4000_ao_get_free_buffer(unsigned long *arg,
- me4000_ao_context_t * ao_context);
+ struct me4000_ao_context *ao_context);
/*-----------------------------------------------------------------------------
Analog input stuff
---------------------------------------------------------------------------*/
-static int me4000_ai_single(me4000_ai_single_t *, me4000_ai_context_t *);
+static int me4000_ai_single(struct me4000_ai_single *,
+ struct me4000_ai_context *);
static int me4000_ai_ioctl_sing(struct inode *, struct file *, unsigned int,
unsigned long);
@@ -186,68 +171,69 @@ static int me4000_ai_fasync(int fd, struct file *file_p, int mode);
static int me4000_ai_ioctl_ext(struct inode *, struct file *, unsigned int,
unsigned long);
-static int me4000_ai_prepare(me4000_ai_context_t * ai_context);
-static int me4000_ai_reset(me4000_ai_context_t * ai_context);
-static int me4000_ai_config(me4000_ai_config_t *, me4000_ai_context_t *);
-static int me4000_ai_start(me4000_ai_context_t *);
-static int me4000_ai_start_ex(unsigned long *, me4000_ai_context_t *);
-static int me4000_ai_stop(me4000_ai_context_t *);
-static int me4000_ai_immediate_stop(me4000_ai_context_t *);
-static int me4000_ai_ex_trig_enable(me4000_ai_context_t *);
-static int me4000_ai_ex_trig_disable(me4000_ai_context_t *);
-static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t *,
- me4000_ai_context_t *);
-static int me4000_ai_sc_setup(me4000_ai_sc_t * arg,
- me4000_ai_context_t * ai_context);
-static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context);
-static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context);
-static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context);
-static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context);
-static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context);
+static int me4000_ai_prepare(struct me4000_ai_context *ai_context);
+static int me4000_ai_reset(struct me4000_ai_context *ai_context);
+static int me4000_ai_config(struct me4000_ai_config *,
+ struct me4000_ai_context *);
+static int me4000_ai_start(struct me4000_ai_context *);
+static int me4000_ai_start_ex(unsigned long *, struct me4000_ai_context *);
+static int me4000_ai_stop(struct me4000_ai_context *);
+static int me4000_ai_immediate_stop(struct me4000_ai_context *);
+static int me4000_ai_ex_trig_enable(struct me4000_ai_context *);
+static int me4000_ai_ex_trig_disable(struct me4000_ai_context *);
+static int me4000_ai_ex_trig_setup(struct me4000_ai_trigger *,
+ struct me4000_ai_context *);
+static int me4000_ai_sc_setup(struct me4000_ai_sc *arg,
+ struct me4000_ai_context *ai_context);
+static int me4000_ai_offset_enable(struct me4000_ai_context *ai_context);
+static int me4000_ai_offset_disable(struct me4000_ai_context *ai_context);
+static int me4000_ai_fullscale_enable(struct me4000_ai_context *ai_context);
+static int me4000_ai_fullscale_disable(struct me4000_ai_context *ai_context);
+static int me4000_ai_fsm_state(int *arg, struct me4000_ai_context *ai_context);
static int me4000_ai_get_count_buffer(unsigned long *arg,
- me4000_ai_context_t * ai_context);
+ struct me4000_ai_context *ai_context);
/*-----------------------------------------------------------------------------
EEPROM stuff
---------------------------------------------------------------------------*/
-static int me4000_eeprom_read(me4000_eeprom_t * arg,
- me4000_ai_context_t * ai_context);
-static int me4000_eeprom_write(me4000_eeprom_t * arg,
- me4000_ai_context_t * ai_context);
-static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context,
- unsigned long cmd, int length);
-static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd,
- int length);
+static int me4000_eeprom_read(struct me4000_eeprom *arg,
+ struct me4000_ai_context *ai_context);
+static int me4000_eeprom_write(struct me4000_eeprom *arg,
+ struct me4000_ai_context *ai_context);
/*-----------------------------------------------------------------------------
Digital I/O stuff
---------------------------------------------------------------------------*/
static int me4000_dio_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
-static int me4000_dio_config(me4000_dio_config_t *, me4000_dio_context_t *);
-static int me4000_dio_get_byte(me4000_dio_byte_t *, me4000_dio_context_t *);
-static int me4000_dio_set_byte(me4000_dio_byte_t *, me4000_dio_context_t *);
-static int me4000_dio_reset(me4000_dio_context_t *);
+static int me4000_dio_config(struct me4000_dio_config *,
+ struct me4000_dio_context *);
+static int me4000_dio_get_byte(struct me4000_dio_byte *,
+ struct me4000_dio_context *);
+static int me4000_dio_set_byte(struct me4000_dio_byte *,
+ struct me4000_dio_context *);
+static int me4000_dio_reset(struct me4000_dio_context *);
/*-----------------------------------------------------------------------------
Counter stuff
---------------------------------------------------------------------------*/
static int me4000_cnt_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
-static int me4000_cnt_config(me4000_cnt_config_t *, me4000_cnt_context_t *);
-static int me4000_cnt_read(me4000_cnt_t *, me4000_cnt_context_t *);
-static int me4000_cnt_write(me4000_cnt_t *, me4000_cnt_context_t *);
-static int me4000_cnt_reset(me4000_cnt_context_t *);
+static int me4000_cnt_config(struct me4000_cnt_config *,
+ struct me4000_cnt_context *);
+static int me4000_cnt_read(struct me4000_cnt *, struct me4000_cnt_context *);
+static int me4000_cnt_write(struct me4000_cnt *, struct me4000_cnt_context *);
+static int me4000_cnt_reset(struct me4000_cnt_context *);
/*-----------------------------------------------------------------------------
External interrupt routines
---------------------------------------------------------------------------*/
static int me4000_ext_int_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
-static int me4000_ext_int_enable(me4000_ext_int_context_t *);
-static int me4000_ext_int_disable(me4000_ext_int_context_t *);
+static int me4000_ext_int_enable(struct me4000_ext_int_context *);
+static int me4000_ext_int_disable(struct me4000_ext_int_context *);
static int me4000_ext_int_count(unsigned long *arg,
- me4000_ext_int_context_t * ext_int_context);
+ struct me4000_ext_int_context *ext_int_context);
static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode);
/*-----------------------------------------------------------------------------
@@ -260,27 +246,18 @@ static irqreturn_t me4000_ext_int_isr(int, void *);
/*-----------------------------------------------------------------------------
Inline functions
---------------------------------------------------------------------------*/
-static int inline me4000_buf_count(me4000_circ_buf_t, int);
-static int inline me4000_buf_space(me4000_circ_buf_t, int);
-static int inline me4000_space_to_end(me4000_circ_buf_t, int);
-static int inline me4000_values_to_end(me4000_circ_buf_t, int);
-
-static void inline me4000_outb(unsigned char value, unsigned long port);
-static void inline me4000_outl(unsigned long value, unsigned long port);
-static unsigned long inline me4000_inl(unsigned long port);
-static unsigned char inline me4000_inb(unsigned long port);
-static int me4000_buf_count(me4000_circ_buf_t buf, int size)
+static int inline me4000_buf_count(struct me4000_circ_buf buf, int size)
{
return ((buf.head - buf.tail) & (size - 1));
}
-static int me4000_buf_space(me4000_circ_buf_t buf, int size)
+static int inline me4000_buf_space(struct me4000_circ_buf buf, int size)
{
return ((buf.tail - (buf.head + 1)) & (size - 1));
}
-static int me4000_values_to_end(me4000_circ_buf_t buf, int size)
+static int inline me4000_values_to_end(struct me4000_circ_buf buf, int size)
{
int end;
int n;
@@ -289,7 +266,7 @@ static int me4000_values_to_end(me4000_circ_buf_t buf, int size)
return (n < end) ? n : end;
}
-static int me4000_space_to_end(me4000_circ_buf_t buf, int size)
+static int inline me4000_space_to_end(struct me4000_circ_buf buf, int size)
{
int end;
int n;
@@ -299,19 +276,19 @@ static int me4000_space_to_end(me4000_circ_buf_t buf, int size)
return (n <= end) ? n : (end + 1);
}
-static void me4000_outb(unsigned char value, unsigned long port)
+static void inline me4000_outb(unsigned char value, unsigned long port)
{
PORT_PDEBUG("--> 0x%02X port 0x%04lX\n", value, port);
outb(value, port);
}
-static void me4000_outl(unsigned long value, unsigned long port)
+static void inline me4000_outl(unsigned long value, unsigned long port)
{
PORT_PDEBUG("--> 0x%08lX port 0x%04lX\n", value, port);
outl(value, port);
}
-static unsigned long me4000_inl(unsigned long port)
+static unsigned long inline me4000_inl(unsigned long port)
{
unsigned long value;
value = inl(port);
@@ -319,7 +296,7 @@ static unsigned long me4000_inl(unsigned long port)
return value;
}
-static unsigned char me4000_inb(unsigned long port)
+static unsigned char inline me4000_inb(unsigned long port)
{
unsigned char value;
value = inb(port);
@@ -327,102 +304,102 @@ static unsigned char me4000_inb(unsigned long port)
return value;
}
-struct pci_driver me4000_driver = {
+static struct pci_driver me4000_driver = {
.name = ME4000_NAME,
.id_table = me4000_pci_table,
.probe = me4000_probe
};
static struct file_operations me4000_ao_fops_sing = {
- owner:THIS_MODULE,
- write:me4000_ao_write_sing,
- ioctl:me4000_ao_ioctl_sing,
- open:me4000_open,
- release:me4000_release,
+ .owner = THIS_MODULE,
+ .write = me4000_ao_write_sing,
+ .ioctl = me4000_ao_ioctl_sing,
+ .open = me4000_open,
+ .release = me4000_release,
};
static struct file_operations me4000_ao_fops_wrap = {
- owner:THIS_MODULE,
- write:me4000_ao_write_wrap,
- ioctl:me4000_ao_ioctl_wrap,
- open:me4000_open,
- release:me4000_release,
+ .owner = THIS_MODULE,
+ .write = me4000_ao_write_wrap,
+ .ioctl = me4000_ao_ioctl_wrap,
+ .open = me4000_open,
+ .release = me4000_release,
};
static struct file_operations me4000_ao_fops_cont = {
- owner:THIS_MODULE,
- write:me4000_ao_write_cont,
- poll:me4000_ao_poll_cont,
- ioctl:me4000_ao_ioctl_cont,
- open:me4000_open,
- release:me4000_release,
- fsync:me4000_ao_fsync_cont,
+ .owner = THIS_MODULE,
+ .write = me4000_ao_write_cont,
+ .poll = me4000_ao_poll_cont,
+ .ioctl = me4000_ao_ioctl_cont,
+ .open = me4000_open,
+ .release = me4000_release,
+ .fsync = me4000_ao_fsync_cont,
};
static struct file_operations me4000_ai_fops_sing = {
- owner:THIS_MODULE,
- ioctl:me4000_ai_ioctl_sing,
- open:me4000_open,
- release:me4000_release,
+ .owner = THIS_MODULE,
+ .ioctl = me4000_ai_ioctl_sing,
+ .open = me4000_open,
+ .release = me4000_release,
};
static struct file_operations me4000_ai_fops_cont_sw = {
- owner:THIS_MODULE,
- read:me4000_ai_read,
- poll:me4000_ai_poll,
- ioctl:me4000_ai_ioctl_sw,
- open:me4000_open,
- release:me4000_release,
- fasync:me4000_ai_fasync,
+ .owner = THIS_MODULE,
+ .read = me4000_ai_read,
+ .poll = me4000_ai_poll,
+ .ioctl = me4000_ai_ioctl_sw,
+ .open = me4000_open,
+ .release = me4000_release,
+ .fasync = me4000_ai_fasync,
};
static struct file_operations me4000_ai_fops_cont_et = {
- owner:THIS_MODULE,
- read:me4000_ai_read,
- poll:me4000_ai_poll,
- ioctl:me4000_ai_ioctl_ext,
- open:me4000_open,
- release:me4000_release,
+ .owner = THIS_MODULE,
+ .read = me4000_ai_read,
+ .poll = me4000_ai_poll,
+ .ioctl = me4000_ai_ioctl_ext,
+ .open = me4000_open,
+ .release = me4000_release,
};
static struct file_operations me4000_ai_fops_cont_et_value = {
- owner:THIS_MODULE,
- read:me4000_ai_read,
- poll:me4000_ai_poll,
- ioctl:me4000_ai_ioctl_ext,
- open:me4000_open,
- release:me4000_release,
+ .owner = THIS_MODULE,
+ .read = me4000_ai_read,
+ .poll = me4000_ai_poll,
+ .ioctl = me4000_ai_ioctl_ext,
+ .open = me4000_open,
+ .release = me4000_release,
};
static struct file_operations me4000_ai_fops_cont_et_chanlist = {
- owner:THIS_MODULE,
- read:me4000_ai_read,
- poll:me4000_ai_poll,
- ioctl:me4000_ai_ioctl_ext,
- open:me4000_open,
- release:me4000_release,
+ .owner = THIS_MODULE,
+ .read = me4000_ai_read,
+ .poll = me4000_ai_poll,
+ .ioctl = me4000_ai_ioctl_ext,
+ .open = me4000_open,
+ .release = me4000_release,
};
static struct file_operations me4000_dio_fops = {
- owner:THIS_MODULE,
- ioctl:me4000_dio_ioctl,
- open:me4000_open,
- release:me4000_release,
+ .owner = THIS_MODULE,
+ .ioctl = me4000_dio_ioctl,
+ .open = me4000_open,
+ .release = me4000_release,
};
static struct file_operations me4000_cnt_fops = {
- owner:THIS_MODULE,
- ioctl:me4000_cnt_ioctl,
- open:me4000_open,
- release:me4000_release,
+ .owner = THIS_MODULE,
+ .ioctl = me4000_cnt_ioctl,
+ .open = me4000_open,
+ .release = me4000_release,
};
static struct file_operations me4000_ext_int_fops = {
- owner:THIS_MODULE,
- ioctl:me4000_ext_int_ioctl,
- open:me4000_open,
- release:me4000_release,
- fasync:me4000_ext_int_fasync,
+ .owner = THIS_MODULE,
+ .ioctl = me4000_ext_int_ioctl,
+ .open = me4000_open,
+ .release = me4000_release,
+ .fasync = me4000_ext_int_fasync,
};
static struct file_operations *me4000_ao_fops_array[] = {
@@ -439,9 +416,9 @@ static struct file_operations *me4000_ai_fops_array[] = {
&me4000_ai_fops_cont_et_chanlist, // work through one channel list by external trigger
};
-int __init me4000_init_module(void)
+static int __init me4000_init_module(void)
{
- int result = 0;
+ int result;
CALL_PDEBUG("init_module() is executed\n");
@@ -533,26 +510,26 @@ int __init me4000_init_module(void)
return 0;
- INIT_ERROR_7:
+INIT_ERROR_7:
unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME);
- INIT_ERROR_6:
+INIT_ERROR_6:
unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME);
- INIT_ERROR_5:
+INIT_ERROR_5:
unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME);
- INIT_ERROR_4:
+INIT_ERROR_4:
unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME);
- INIT_ERROR_3:
+INIT_ERROR_3:
unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME);
- INIT_ERROR_2:
+INIT_ERROR_2:
pci_unregister_driver(&me4000_driver);
clear_board_info_list();
- INIT_ERROR_1:
+INIT_ERROR_1:
return result;
}
@@ -562,18 +539,18 @@ static void clear_board_info_list(void)
{
struct list_head *board_p;
struct list_head *dac_p;
- me4000_info_t *board_info;
- me4000_ao_context_t *ao_context;
+ struct me4000_info *board_info;
+ struct me4000_ao_context *ao_context;
/* Clear context lists */
for (board_p = me4000_board_info_list.next;
board_p != &me4000_board_info_list; board_p = board_p->next) {
- board_info = list_entry(board_p, me4000_info_t, list);
+ board_info = list_entry(board_p, struct me4000_info, list);
/* Clear analog output context list */
while (!list_empty(&board_info->ao_context_list)) {
dac_p = board_info->ao_context_list.next;
ao_context =
- list_entry(dac_p, me4000_ao_context_t, list);
+ list_entry(dac_p, struct me4000_ao_context, list);
me4000_ao_reset(ao_context);
free_irq(ao_context->irq, ao_context);
if (ao_context->circ_buf.buf)
@@ -600,14 +577,14 @@ static void clear_board_info_list(void)
/* Clear the board info list */
while (!list_empty(&me4000_board_info_list)) {
board_p = me4000_board_info_list.next;
- board_info = list_entry(board_p, me4000_info_t, list);
+ board_info = list_entry(board_p, struct me4000_info, list);
pci_release_regions(board_info->pci_dev_p);
list_del(board_p);
kfree(board_info);
}
}
-static int get_registers(struct pci_dev *dev, me4000_info_t * board_info)
+static int get_registers(struct pci_dev *dev, struct me4000_info *board_info)
{
/*--------------------------- plx regbase ---------------------------------*/
@@ -667,20 +644,20 @@ static int get_registers(struct pci_dev *dev, me4000_info_t * board_info)
}
static int init_board_info(struct pci_dev *pci_dev_p,
- me4000_info_t * board_info)
+ struct me4000_info *board_info)
{
int i;
int result;
struct list_head *board_p;
board_info->pci_dev_p = pci_dev_p;
- for (i = 0; i < ME4000_BOARD_VERSIONS; i++) {
+ for (i = 0; i < ARRAY_SIZE(me4000_boards); i++) {
if (me4000_boards[i].device_id == pci_dev_p->device) {
board_info->board_p = &me4000_boards[i];
break;
}
}
- if (i == ME4000_BOARD_VERSIONS) {
+ if (i == ARRAY_SIZE(me4000_boards)) {
printk(KERN_ERR
"ME4000:init_board_info():Device ID not valid\n");
return -ENODEV;
@@ -755,21 +732,21 @@ static int init_board_info(struct pci_dev *pci_dev_p,
return 0;
}
-static int alloc_ao_contexts(me4000_info_t * info)
+static int alloc_ao_contexts(struct me4000_info *info)
{
int i;
int err;
- me4000_ao_context_t *ao_context;
+ struct me4000_ao_context *ao_context;
for (i = 0; i < info->board_p->ao.count; i++) {
- ao_context = kmalloc(sizeof(me4000_ao_context_t), GFP_KERNEL);
+ ao_context = kzalloc(sizeof(struct me4000_ao_context),
+ GFP_KERNEL);
if (!ao_context) {
printk(KERN_ERR
"alloc_ao_contexts():Can't get memory for ao context\n");
release_ao_contexts(info);
return -ENOMEM;
}
- memset(ao_context, 0, sizeof(me4000_ao_context_t));
spin_lock_init(&ao_context->use_lock);
spin_lock_init(&ao_context->int_lock);
@@ -780,15 +757,13 @@ static int alloc_ao_contexts(me4000_info_t * info)
if (info->board_p->ao.fifo_count) {
/* Allocate circular buffer */
ao_context->circ_buf.buf =
- kmalloc(ME4000_AO_BUFFER_SIZE, GFP_KERNEL);
+ kzalloc(ME4000_AO_BUFFER_SIZE, GFP_KERNEL);
if (!ao_context->circ_buf.buf) {
printk(KERN_ERR
"alloc_ao_contexts():Can't get circular buffer\n");
release_ao_contexts(info);
return -ENOMEM;
}
- memset(ao_context->circ_buf.buf, 0,
- ME4000_AO_BUFFER_SIZE);
/* Clear the circular buffer */
ao_context->circ_buf.head = 0;
@@ -872,9 +847,8 @@ static int alloc_ao_contexts(me4000_info_t * info)
ME4000_NAME, ao_context);
if (err) {
printk(KERN_ERR
- "alloc_ao_contexts():Can't get interrupt line");
- if (ao_context->circ_buf.buf)
- kfree(ao_context->circ_buf.buf);
+ "%s:Can't get interrupt line", __func__);
+ kfree(ao_context->circ_buf.buf);
kfree(ao_context);
release_ao_contexts(info);
return -ENODEV;
@@ -888,35 +862,34 @@ static int alloc_ao_contexts(me4000_info_t * info)
return 0;
}
-static void release_ao_contexts(me4000_info_t * board_info)
+static void release_ao_contexts(struct me4000_info *board_info)
{
struct list_head *dac_p;
- me4000_ao_context_t *ao_context;
+ struct me4000_ao_context *ao_context;
/* Clear analog output context list */
while (!list_empty(&board_info->ao_context_list)) {
dac_p = board_info->ao_context_list.next;
- ao_context = list_entry(dac_p, me4000_ao_context_t, list);
+ ao_context = list_entry(dac_p, struct me4000_ao_context, list);
free_irq(ao_context->irq, ao_context);
- if (ao_context->circ_buf.buf)
- kfree(ao_context->circ_buf.buf);
+ kfree(ao_context->circ_buf.buf);
list_del(dac_p);
kfree(ao_context);
}
}
-static int alloc_ai_context(me4000_info_t * info)
+static int alloc_ai_context(struct me4000_info *info)
{
- me4000_ai_context_t *ai_context;
+ struct me4000_ai_context *ai_context;
if (info->board_p->ai.count) {
- ai_context = kmalloc(sizeof(me4000_ai_context_t), GFP_KERNEL);
+ ai_context = kzalloc(sizeof(struct me4000_ai_context),
+ GFP_KERNEL);
if (!ai_context) {
printk(KERN_ERR
"ME4000:alloc_ai_context():Can't get memory for ai context\n");
return -ENOMEM;
}
- memset(ai_context, 0, sizeof(me4000_ai_context_t));
info->ai_context = ai_context;
@@ -958,18 +931,18 @@ static int alloc_ai_context(me4000_info_t * info)
return 0;
}
-static int alloc_dio_context(me4000_info_t * info)
+static int alloc_dio_context(struct me4000_info *info)
{
- me4000_dio_context_t *dio_context;
+ struct me4000_dio_context *dio_context;
if (info->board_p->dio.count) {
- dio_context = kmalloc(sizeof(me4000_dio_context_t), GFP_KERNEL);
+ dio_context = kzalloc(sizeof(struct me4000_dio_context),
+ GFP_KERNEL);
if (!dio_context) {
printk(KERN_ERR
"ME4000:alloc_dio_context():Can't get memory for dio context\n");
return -ENOMEM;
}
- memset(dio_context, 0, sizeof(me4000_dio_context_t));
info->dio_context = dio_context;
@@ -995,18 +968,18 @@ static int alloc_dio_context(me4000_info_t * info)
return 0;
}
-static int alloc_cnt_context(me4000_info_t * info)
+static int alloc_cnt_context(struct me4000_info *info)
{
- me4000_cnt_context_t *cnt_context;
+ struct me4000_cnt_context *cnt_context;
if (info->board_p->cnt.count) {
- cnt_context = kmalloc(sizeof(me4000_cnt_context_t), GFP_KERNEL);
+ cnt_context = kzalloc(sizeof(struct me4000_cnt_context),
+ GFP_KERNEL);
if (!cnt_context) {
printk(KERN_ERR
"ME4000:alloc_cnt_context():Can't get memory for cnt context\n");
return -ENOMEM;
}
- memset(cnt_context, 0, sizeof(me4000_cnt_context_t));
info->cnt_context = cnt_context;
@@ -1026,19 +999,18 @@ static int alloc_cnt_context(me4000_info_t * info)
return 0;
}
-static int alloc_ext_int_context(me4000_info_t * info)
+static int alloc_ext_int_context(struct me4000_info *info)
{
- me4000_ext_int_context_t *ext_int_context;
+ struct me4000_ext_int_context *ext_int_context;
if (info->board_p->cnt.count) {
ext_int_context =
- kmalloc(sizeof(me4000_ext_int_context_t), GFP_KERNEL);
+ kzalloc(sizeof(struct me4000_ext_int_context), GFP_KERNEL);
if (!ext_int_context) {
printk(KERN_ERR
"ME4000:alloc_ext_int_context():Can't get memory for cnt context\n");
return -ENOMEM;
}
- memset(ext_int_context, 0, sizeof(me4000_ext_int_context_t));
info->ext_int_context = ext_int_context;
@@ -1060,19 +1032,18 @@ static int alloc_ext_int_context(me4000_info_t * info)
static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int result = 0;
- me4000_info_t *board_info;
+ struct me4000_info *board_info;
CALL_PDEBUG("me4000_probe() is executed\n");
/* Allocate structure for board context */
- board_info = kmalloc(sizeof(me4000_info_t), GFP_KERNEL);
+ board_info = kzalloc(sizeof(struct me4000_info), GFP_KERNEL);
if (!board_info) {
printk(KERN_ERR
"ME4000:Can't get memory for board info structure\n");
result = -ENOMEM;
goto PROBE_ERROR_1;
}
- memset(board_info, 0, sizeof(me4000_info_t));
/* Add to global linked list */
list_add_tail(&board_info->list, &me4000_board_info_list);
@@ -1080,70 +1051,70 @@ static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* Get the PCI base registers */
result = get_registers(dev, board_info);
if (result) {
- printk(KERN_ERR "me4000_probe():Cannot get registers\n");
+ printk(KERN_ERR "%s:Cannot get registers\n", __func__);
goto PROBE_ERROR_2;
}
/* Enable the device */
result = pci_enable_device(dev);
if (result < 0) {
- printk(KERN_ERR "me4000_probe():Cannot enable PCI device\n");
+ printk(KERN_ERR "%s:Cannot enable PCI device\n", __func__);
goto PROBE_ERROR_2;
}
/* Request the PCI register regions */
result = pci_request_regions(dev, ME4000_NAME);
if (result < 0) {
- printk(KERN_ERR "me4000_probe():Cannot request I/O regions\n");
+ printk(KERN_ERR "%s:Cannot request I/O regions\n", __func__);
goto PROBE_ERROR_2;
}
/* Initialize board info */
result = init_board_info(dev, board_info);
if (result) {
- printk(KERN_ERR "me4000_probe():Cannot init baord info\n");
+ printk(KERN_ERR "%s:Cannot init baord info\n", __func__);
goto PROBE_ERROR_3;
}
/* Download the xilinx firmware */
result = me4000_xilinx_download(board_info);
if (result) {
- printk(KERN_ERR "me4000_probe:Can't download firmware\n");
+ printk(KERN_ERR "%s:Can't download firmware\n", __func__);
goto PROBE_ERROR_3;
}
/* Make a hardware reset */
result = me4000_reset_board(board_info);
if (result) {
- printk(KERN_ERR "me4000_probe:Can't reset board\n");
+ printk(KERN_ERR "%s :Can't reset board\n", __func__);
goto PROBE_ERROR_3;
}
/* Allocate analog output context structures */
result = alloc_ao_contexts(board_info);
if (result) {
- printk(KERN_ERR "me4000_probe():Cannot allocate ao contexts\n");
+ printk(KERN_ERR "%s:Cannot allocate ao contexts\n", __func__);
goto PROBE_ERROR_3;
}
/* Allocate analog input context */
result = alloc_ai_context(board_info);
if (result) {
- printk(KERN_ERR "me4000_probe():Cannot allocate ai context\n");
+ printk(KERN_ERR "%s:Cannot allocate ai context\n", __func__);
goto PROBE_ERROR_4;
}
/* Allocate digital I/O context */
result = alloc_dio_context(board_info);
if (result) {
- printk(KERN_ERR "me4000_probe():Cannot allocate dio context\n");
+ printk(KERN_ERR "%s:Cannot allocate dio context\n", __func__);
goto PROBE_ERROR_5;
}
/* Allocate counter context */
result = alloc_cnt_context(board_info);
if (result) {
- printk(KERN_ERR "me4000_probe():Cannot allocate cnt context\n");
+ printk(KERN_ERR "%s:Cannot allocate cnt context\n", __func__);
goto PROBE_ERROR_6;
}
@@ -1151,36 +1122,36 @@ static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id)
result = alloc_ext_int_context(board_info);
if (result) {
printk(KERN_ERR
- "me4000_probe():Cannot allocate ext_int context\n");
+ "%s:Cannot allocate ext_int context\n", __func__);
goto PROBE_ERROR_7;
}
return 0;
- PROBE_ERROR_7:
+PROBE_ERROR_7:
kfree(board_info->cnt_context);
- PROBE_ERROR_6:
+PROBE_ERROR_6:
kfree(board_info->dio_context);
- PROBE_ERROR_5:
+PROBE_ERROR_5:
kfree(board_info->ai_context);
- PROBE_ERROR_4:
+PROBE_ERROR_4:
release_ao_contexts(board_info);
- PROBE_ERROR_3:
+PROBE_ERROR_3:
pci_release_regions(dev);
- PROBE_ERROR_2:
+PROBE_ERROR_2:
list_del(&board_info->list);
kfree(board_info);
- PROBE_ERROR_1:
+PROBE_ERROR_1:
return result;
}
-static int me4000_xilinx_download(me4000_info_t * info)
+static int me4000_xilinx_download(struct me4000_info *info)
{
int size = 0;
u32 value = 0;
@@ -1211,7 +1182,7 @@ static int me4000_xilinx_download(me4000_info_t * info)
/* Wait until /INIT pin is set */
udelay(20);
if (!inl(info->plx_regbase + PLX_INTCSR) & 0x20) {
- printk(KERN_ERR "me4000_xilinx_download():Can't init Xilinx\n");
+ printk(KERN_ERR "%s:Can't init Xilinx\n", __func__);
return -EIO;
}
@@ -1232,7 +1203,7 @@ static int me4000_xilinx_download(me4000_info_t * info)
/* Check if BUSY flag is low */
if (inl(info->plx_regbase + PLX_ICR) & 0x20) {
printk(KERN_ERR
- "me4000_xilinx_download():Xilinx is still busy (idx = %d)\n",
+ "%s:Xilinx is still busy (idx = %d)\n", __func__,
idx);
return -EIO;
}
@@ -1246,9 +1217,9 @@ static int me4000_xilinx_download(me4000_info_t * info)
PDEBUG("me4000_xilinx_download():Download was successful\n");
} else {
printk(KERN_ERR
- "ME4000:me4000_xilinx_download():DONE flag is not set\n");
+ "ME4000:%s:DONE flag is not set\n", __func__);
printk(KERN_ERR
- "ME4000:me4000_xilinx_download():Download not succesful\n");
+ "ME4000:%s:Download not succesful\n", __func__);
return -EIO;
}
@@ -1260,7 +1231,7 @@ static int me4000_xilinx_download(me4000_info_t * info)
return 0;
}
-static int me4000_reset_board(me4000_info_t * info)
+static int me4000_reset_board(struct me4000_info *info)
{
unsigned long icr;
@@ -1314,12 +1285,12 @@ static int me4000_open(struct inode *inode_p, struct file *file_p)
int err = 0;
int i;
struct list_head *ptr;
- me4000_info_t *board_info = NULL;
- me4000_ao_context_t *ao_context = NULL;
- me4000_ai_context_t *ai_context = NULL;
- me4000_dio_context_t *dio_context = NULL;
- me4000_cnt_context_t *cnt_context = NULL;
- me4000_ext_int_context_t *ext_int_context = NULL;
+ struct me4000_info *board_info = NULL;
+ struct me4000_ao_context *ao_context = NULL;
+ struct me4000_ai_context *ai_context = NULL;
+ struct me4000_dio_context *dio_context = NULL;
+ struct me4000_cnt_context *cnt_context = NULL;
+ struct me4000_ext_int_context *ext_int_context = NULL;
CALL_PDEBUG("me4000_open() is executed\n");
@@ -1335,7 +1306,7 @@ static int me4000_open(struct inode *inode_p, struct file *file_p)
/* Search for the board context */
for (ptr = me4000_board_info_list.next, i = 0;
ptr != &me4000_board_info_list; ptr = ptr->next, i++) {
- board_info = list_entry(ptr, me4000_info_t, list);
+ board_info = list_entry(ptr, struct me4000_info, list);
if (i == board)
break;
}
@@ -1351,7 +1322,8 @@ static int me4000_open(struct inode *inode_p, struct file *file_p)
for (ptr = board_info->ao_context_list.next, i = 0;
ptr != &board_info->ao_context_list;
ptr = ptr->next, i++) {
- ao_context = list_entry(ptr, me4000_ao_context_t, list);
+ ao_context = list_entry(ptr, struct me4000_ao_context,
+ list);
if (i == dev)
break;
}
@@ -1415,7 +1387,7 @@ static int me4000_open(struct inode *inode_p, struct file *file_p)
/* Search for the board context */
for (ptr = me4000_board_info_list.next, i = 0;
ptr != &me4000_board_info_list; ptr = ptr->next, i++) {
- board_info = list_entry(ptr, me4000_info_t, list);
+ board_info = list_entry(ptr, struct me4000_info, list);
if (i == board)
break;
}
@@ -1469,7 +1441,7 @@ static int me4000_open(struct inode *inode_p, struct file *file_p)
/* Search for the board context */
for (ptr = me4000_board_info_list.next;
ptr != &me4000_board_info_list; ptr = ptr->next) {
- board_info = list_entry(ptr, me4000_info_t, list);
+ board_info = list_entry(ptr, struct me4000_info, list);
if (board_info->board_count == board)
break;
}
@@ -1514,7 +1486,7 @@ static int me4000_open(struct inode *inode_p, struct file *file_p)
/* Search for the board context */
for (ptr = me4000_board_info_list.next;
ptr != &me4000_board_info_list; ptr = ptr->next) {
- board_info = list_entry(ptr, me4000_info_t, list);
+ board_info = list_entry(ptr, struct me4000_info, list);
if (board_info->board_count == board)
break;
}
@@ -1557,7 +1529,7 @@ static int me4000_open(struct inode *inode_p, struct file *file_p)
/* Search for the board context */
for (ptr = me4000_board_info_list.next;
ptr != &me4000_board_info_list; ptr = ptr->next) {
- board_info = list_entry(ptr, me4000_info_t, list);
+ board_info = list_entry(ptr, struct me4000_info, list);
if (board_info->board_count == board)
break;
}
@@ -1613,11 +1585,11 @@ static int me4000_open(struct inode *inode_p, struct file *file_p)
static int me4000_release(struct inode *inode_p, struct file *file_p)
{
- me4000_ao_context_t *ao_context;
- me4000_ai_context_t *ai_context;
- me4000_dio_context_t *dio_context;
- me4000_cnt_context_t *cnt_context;
- me4000_ext_int_context_t *ext_int_context;
+ struct me4000_ao_context *ao_context;
+ struct me4000_ai_context *ai_context;
+ struct me4000_dio_context *dio_context;
+ struct me4000_cnt_context *cnt_context;
+ struct me4000_ext_int_context *ext_int_context;
CALL_PDEBUG("me4000_release() is executed\n");
@@ -1677,7 +1649,7 @@ static int me4000_release(struct inode *inode_p, struct file *file_p)
/*------------------------------- Analog output stuff --------------------------------------*/
-static int me4000_ao_prepare(me4000_ao_context_t * ao_context)
+static int me4000_ao_prepare(struct me4000_ao_context *ao_context)
{
unsigned long flags;
@@ -1756,7 +1728,7 @@ static int me4000_ao_prepare(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_reset(me4000_ao_context_t * ao_context)
+static int me4000_ao_reset(struct me4000_ao_context *ao_context)
{
u32 tmp;
wait_queue_head_t queue;
@@ -1777,9 +1749,10 @@ static int me4000_ao_reset(me4000_ao_context_t * ao_context)
tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
me4000_outl(tmp, ao_context->ctrl_reg);
- while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
- sleep_on_timeout(&queue, 1);
- }
+ wait_event_timeout(queue,
+ (inl(ao_context->status_reg) &
+ ME4000_AO_STATUS_BIT_FSM) == 0,
+ 1);
/* Set to transparent mode */
me4000_ao_simultaneous_disable(ao_context);
@@ -1812,9 +1785,10 @@ static int me4000_ao_reset(me4000_ao_context_t * ao_context)
me4000_outl(tmp, ao_context->ctrl_reg);
spin_unlock_irqrestore(&ao_context->int_lock, flags);
- while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
- sleep_on_timeout(&queue, 1);
- }
+ wait_event_timeout(queue,
+ (inl(ao_context->status_reg) &
+ ME4000_AO_STATUS_BIT_FSM) == 0,
+ 1);
/* Clear the circular buffer */
ao_context->circ_buf.head = 0;
@@ -1853,9 +1827,9 @@ static int me4000_ao_reset(me4000_ao_context_t * ao_context)
}
static ssize_t me4000_ao_write_sing(struct file *filep, const char *buff,
- size_t cnt, loff_t * offp)
+ size_t cnt, loff_t *offp)
{
- me4000_ao_context_t *ao_context = filep->private_data;
+ struct me4000_ao_context *ao_context = filep->private_data;
u32 value;
const u16 *buffer = (const u16 *)buff;
@@ -1863,13 +1837,13 @@ static ssize_t me4000_ao_write_sing(struct file *filep, const char *buff,
if (cnt != 2) {
printk(KERN_ERR
- "me4000_ao_write_sing():Write count is not 2\n");
+ "%s:Write count is not 2\n", __func__);
return -EINVAL;
}
if (get_user(value, buffer)) {
printk(KERN_ERR
- "me4000_ao_write_sing():Cannot copy data from user\n");
+ "%s:Cannot copy data from user\n", __func__);
return -EFAULT;
}
@@ -1879,9 +1853,9 @@ static ssize_t me4000_ao_write_sing(struct file *filep, const char *buff,
}
static ssize_t me4000_ao_write_wrap(struct file *filep, const char *buff,
- size_t cnt, loff_t * offp)
+ size_t cnt, loff_t *offp)
{
- me4000_ao_context_t *ao_context = filep->private_data;
+ struct me4000_ao_context *ao_context = filep->private_data;
size_t i;
u32 value;
u32 tmp;
@@ -1893,13 +1867,13 @@ static ssize_t me4000_ao_write_wrap(struct file *filep, const char *buff,
/* Check if a conversion is already running */
if (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
printk(KERN_ERR
- "ME4000:me4000_ao_write_wrap():There is already a conversion running\n");
+ "%s:There is already a conversion running\n", __func__);
return -EBUSY;
}
if (count > ME4000_AO_FIFO_COUNT) {
printk(KERN_ERR
- "me4000_ao_write_wrap():Can't load more than %d values\n",
+ "%s:Can't load more than %d values\n", __func__,
ME4000_AO_FIFO_COUNT);
return -ENOSPC;
}
@@ -1914,7 +1888,7 @@ static ssize_t me4000_ao_write_wrap(struct file *filep, const char *buff,
for (i = 0; i < count; i++) {
if (get_user(value, buffer + i)) {
printk(KERN_ERR
- "me4000_ao_write_single():Cannot copy data from user\n");
+ "%s:Cannot copy data from user\n", __func__);
return -EFAULT;
}
if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG)
@@ -1928,9 +1902,9 @@ static ssize_t me4000_ao_write_wrap(struct file *filep, const char *buff,
}
static ssize_t me4000_ao_write_cont(struct file *filep, const char *buff,
- size_t cnt, loff_t * offp)
+ size_t cnt, loff_t *offp)
{
- me4000_ao_context_t *ao_context = filep->private_data;
+ struct me4000_ao_context *ao_context = filep->private_data;
const u16 *buffer = (const u16 *)buff;
size_t count = cnt / 2;
unsigned long flags;
@@ -2154,9 +2128,9 @@ static ssize_t me4000_ao_write_cont(struct file *filep, const char *buff,
return 2 * ret;
}
-static unsigned int me4000_ao_poll_cont(struct file *file_p, poll_table * wait)
+static unsigned int me4000_ao_poll_cont(struct file *file_p, poll_table *wait)
{
- me4000_ao_context_t *ao_context;
+ struct me4000_ao_context *ao_context;
unsigned long mask = 0;
CALL_PDEBUG("me4000_ao_poll_cont() is executed\n");
@@ -2177,7 +2151,7 @@ static unsigned int me4000_ao_poll_cont(struct file *file_p, poll_table * wait)
static int me4000_ao_fsync_cont(struct file *file_p, struct dentry *dentry_p,
int datasync)
{
- me4000_ao_context_t *ao_context;
+ struct me4000_ao_context *ao_context;
wait_queue_head_t queue;
CALL_PDEBUG("me4000_ao_fsync_cont() is executed\n");
@@ -2187,15 +2161,19 @@ static int me4000_ao_fsync_cont(struct file *file_p, struct dentry *dentry_p,
while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
interruptible_sleep_on_timeout(&queue, 1);
+ wait_event_interruptible_timeout(queue,
+ !(inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM),
+ 1);
if (ao_context->pipe_flag) {
printk(KERN_ERR
- "me4000_ao_fsync_cont():Broken pipe detected\n");
+ "%s:Broken pipe detected\n", __func__);
return -EPIPE;
}
if (signal_pending(current)) {
printk(KERN_ERR
- "me4000_ao_fsync_cont():Wait on state machine interrupted\n");
+ "%s:Wait on state machine interrupted\n",
+ __func__);
return -EINTR;
}
}
@@ -2206,7 +2184,7 @@ static int me4000_ao_fsync_cont(struct file *file_p, struct dentry *dentry_p,
static int me4000_ao_ioctl_sing(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
- me4000_ao_context_t *ao_context;
+ struct me4000_ao_context *ao_context;
CALL_PDEBUG("me4000_ao_ioctl_sing() is executed\n");
@@ -2229,7 +2207,7 @@ static int me4000_ao_ioctl_sing(struct inode *inode_p, struct file *file_p,
case ME4000_AO_PRELOAD_UPDATE:
return me4000_ao_preload_update(ao_context);
case ME4000_GET_USER_INFO:
- return me4000_get_user_info((me4000_user_info_t *) arg,
+ return me4000_get_user_info((struct me4000_user_info *)arg,
ao_context->board_info);
case ME4000_AO_SIMULTANEOUS_EX_TRIG:
return me4000_ao_simultaneous_ex_trig(ao_context);
@@ -2239,8 +2217,9 @@ static int me4000_ao_ioctl_sing(struct inode *inode_p, struct file *file_p,
return me4000_ao_simultaneous_disable(ao_context);
case ME4000_AO_SIMULTANEOUS_UPDATE:
return
- me4000_ao_simultaneous_update((me4000_ao_channel_list_t *)
- arg, ao_context);
+ me4000_ao_simultaneous_update(
+ (struct me4000_ao_channel_list *)arg,
+ ao_context);
case ME4000_AO_EX_TRIG_TIMEOUT:
return me4000_ao_ex_trig_timeout((unsigned long *)arg,
ao_context);
@@ -2258,7 +2237,7 @@ static int me4000_ao_ioctl_sing(struct inode *inode_p, struct file *file_p,
static int me4000_ao_ioctl_wrap(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
- me4000_ao_context_t *ao_context;
+ struct me4000_ao_context *ao_context;
CALL_PDEBUG("me4000_ao_ioctl_wrap() is executed\n");
@@ -2287,7 +2266,7 @@ static int me4000_ao_ioctl_wrap(struct inode *inode_p, struct file *file_p,
case ME4000_AO_EX_TRIG_DISABLE:
return me4000_ao_ex_trig_disable(ao_context);
case ME4000_GET_USER_INFO:
- return me4000_get_user_info((me4000_user_info_t *) arg,
+ return me4000_get_user_info((struct me4000_user_info *)arg,
ao_context->board_info);
case ME4000_AO_FSM_STATE:
return me4000_ao_fsm_state((int *)arg, ao_context);
@@ -2310,7 +2289,7 @@ static int me4000_ao_ioctl_wrap(struct inode *inode_p, struct file *file_p,
static int me4000_ao_ioctl_cont(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
- me4000_ao_context_t *ao_context;
+ struct me4000_ao_context *ao_context;
CALL_PDEBUG("me4000_ao_ioctl_cont() is executed\n");
@@ -2345,7 +2324,7 @@ static int me4000_ao_ioctl_cont(struct inode *inode_p, struct file *file_p,
case ME4000_AO_FSM_STATE:
return me4000_ao_fsm_state((int *)arg, ao_context);
case ME4000_GET_USER_INFO:
- return me4000_get_user_info((me4000_user_info_t *) arg,
+ return me4000_get_user_info((struct me4000_user_info *)arg,
ao_context->board_info);
case ME4000_AO_SYNCHRONOUS_EX_TRIG:
return me4000_ao_synchronous_ex_trig(ao_context);
@@ -2362,7 +2341,8 @@ static int me4000_ao_ioctl_cont(struct inode *inode_p, struct file *file_p,
return 0;
}
-static int me4000_ao_start(unsigned long *arg, me4000_ao_context_t * ao_context)
+static int me4000_ao_start(unsigned long *arg,
+ struct me4000_ao_context *ao_context)
{
u32 tmp;
wait_queue_head_t queue;
@@ -2412,7 +2392,7 @@ static int me4000_ao_start(unsigned long *arg, me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_stop(me4000_ao_context_t * ao_context)
+static int me4000_ao_stop(struct me4000_ao_context *ao_context)
{
u32 tmp;
wait_queue_head_t queue;
@@ -2445,7 +2425,7 @@ static int me4000_ao_stop(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_immediate_stop(me4000_ao_context_t * ao_context)
+static int me4000_ao_immediate_stop(struct me4000_ao_context *ao_context)
{
u32 tmp;
wait_queue_head_t queue;
@@ -2477,8 +2457,8 @@ static int me4000_ao_immediate_stop(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_timer_set_divisor(u32 * arg,
- me4000_ao_context_t * ao_context)
+static int me4000_ao_timer_set_divisor(u32 *arg,
+ struct me4000_ao_context *ao_context)
{
u32 divisor;
u32 tmp;
@@ -2518,7 +2498,7 @@ static int me4000_ao_timer_set_divisor(u32 * arg,
}
static int me4000_ao_ex_trig_set_edge(int *arg,
- me4000_ao_context_t * ao_context)
+ struct me4000_ao_context *ao_context)
{
int mode;
u32 tmp;
@@ -2569,7 +2549,7 @@ static int me4000_ao_ex_trig_set_edge(int *arg,
return 0;
}
-static int me4000_ao_ex_trig_enable(me4000_ao_context_t * ao_context)
+static int me4000_ao_ex_trig_enable(struct me4000_ao_context *ao_context)
{
u32 tmp;
unsigned long flags;
@@ -2593,7 +2573,7 @@ static int me4000_ao_ex_trig_enable(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_ex_trig_disable(me4000_ao_context_t * ao_context)
+static int me4000_ao_ex_trig_disable(struct me4000_ao_context *ao_context)
{
u32 tmp;
unsigned long flags;
@@ -2617,7 +2597,7 @@ static int me4000_ao_ex_trig_disable(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context)
+static int me4000_ao_simultaneous_disable(struct me4000_ao_context *ao_context)
{
u32 tmp;
@@ -2643,7 +2623,7 @@ static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context)
+static int me4000_ao_simultaneous_ex_trig(struct me4000_ao_context *ao_context)
{
u32 tmp;
@@ -2659,7 +2639,7 @@ static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context)
+static int me4000_ao_simultaneous_sw(struct me4000_ao_context *ao_context)
{
u32 tmp;
@@ -2675,13 +2655,13 @@ static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_preload(me4000_ao_context_t * ao_context)
+static int me4000_ao_preload(struct me4000_ao_context *ao_context)
{
CALL_PDEBUG("me4000_ao_preload() is executed\n");
return me4000_ao_simultaneous_sw(ao_context);
}
-static int me4000_ao_preload_update(me4000_ao_context_t * ao_context)
+static int me4000_ao_preload_update(struct me4000_ao_context *ao_context)
{
u32 tmp;
u32 ctrl;
@@ -2705,10 +2685,12 @@ static int me4000_ao_preload_update(me4000_ao_context_t * ao_context)
if (!
(tmp &
(0x1 <<
- (((me4000_ao_context_t *) entry)->index + 16)))) {
+ (((struct me4000_ao_context *)entry)->index
+ + 16)))) {
tmp &=
~(0x1 <<
- (((me4000_ao_context_t *) entry)->index));
+ (((struct me4000_ao_context *)entry)->
+ index));
}
}
}
@@ -2718,18 +2700,19 @@ static int me4000_ao_preload_update(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * arg,
- me4000_ao_context_t * ao_context)
+static int me4000_ao_simultaneous_update(struct me4000_ao_channel_list *arg,
+ struct me4000_ao_context *ao_context)
{
int err;
int i;
u32 tmp;
- me4000_ao_channel_list_t channels;
+ struct me4000_ao_channel_list channels;
CALL_PDEBUG("me4000_ao_simultaneous_update() is executed\n");
/* Copy data from user */
- err = copy_from_user(&channels, arg, sizeof(me4000_ao_channel_list_t));
+ err = copy_from_user(&channels, arg,
+ sizeof(struct me4000_ao_channel_list));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ao_simultaneous_update():Can't copy command\n");
@@ -2737,13 +2720,12 @@ static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * arg,
}
channels.list =
- kmalloc(sizeof(unsigned long) * channels.count, GFP_KERNEL);
+ kzalloc(sizeof(unsigned long) * channels.count, GFP_KERNEL);
if (!channels.list) {
printk(KERN_ERR
"ME4000:me4000_ao_simultaneous_update():Can't get buffer\n");
return -ENOMEM;
}
- memset(channels.list, 0, sizeof(unsigned long) * channels.count);
/* Copy channel list from user */
err =
@@ -2777,7 +2759,7 @@ static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * arg,
return 0;
}
-static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context)
+static int me4000_ao_synchronous_ex_trig(struct me4000_ao_context *ao_context)
{
u32 tmp;
unsigned long flags;
@@ -2813,7 +2795,7 @@ static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context)
+static int me4000_ao_synchronous_sw(struct me4000_ao_context *ao_context)
{
u32 tmp;
unsigned long flags;
@@ -2848,13 +2830,13 @@ static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context)
+static int me4000_ao_synchronous_disable(struct me4000_ao_context *ao_context)
{
return me4000_ao_simultaneous_disable(ao_context);
}
static int me4000_ao_get_free_buffer(unsigned long *arg,
- me4000_ao_context_t * ao_context)
+ struct me4000_ao_context *ao_context)
{
unsigned long c;
int err;
@@ -2864,7 +2846,7 @@ static int me4000_ao_get_free_buffer(unsigned long *arg,
err = copy_to_user(arg, &c, sizeof(unsigned long));
if (err) {
printk(KERN_ERR
- "ME4000:me4000_ao_get_free_buffer():Can't copy to user space\n");
+ "%s:Can't copy to user space\n", __func__);
return -EFAULT;
}
@@ -2872,7 +2854,7 @@ static int me4000_ao_get_free_buffer(unsigned long *arg,
}
static int me4000_ao_ex_trig_timeout(unsigned long *arg,
- me4000_ao_context_t * ao_context)
+ struct me4000_ao_context *ao_context)
{
u32 tmp;
wait_queue_head_t queue;
@@ -2928,7 +2910,7 @@ static int me4000_ao_ex_trig_timeout(unsigned long *arg,
return 0;
}
-static int me4000_ao_enable_do(me4000_ao_context_t * ao_context)
+static int me4000_ao_enable_do(struct me4000_ao_context *ao_context)
{
u32 tmp;
unsigned long flags;
@@ -2959,7 +2941,7 @@ static int me4000_ao_enable_do(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_disable_do(me4000_ao_context_t * ao_context)
+static int me4000_ao_disable_do(struct me4000_ao_context *ao_context)
{
u32 tmp;
unsigned long flags;
@@ -2989,7 +2971,7 @@ static int me4000_ao_disable_do(me4000_ao_context_t * ao_context)
return 0;
}
-static int me4000_ao_fsm_state(int *arg, me4000_ao_context_t * ao_context)
+static int me4000_ao_fsm_state(int *arg, struct me4000_ao_context *ao_context)
{
unsigned long tmp;
@@ -3012,9 +2994,9 @@ static int me4000_ao_fsm_state(int *arg, me4000_ao_context_t * ao_context)
return 0;
}
-/*------------------------------- Analog input stuff --------------------------------------*/
+/*------------------------- Analog input stuff -------------------------------*/
-static int me4000_ai_prepare(me4000_ai_context_t * ai_context)
+static int me4000_ai_prepare(struct me4000_ai_context *ai_context)
{
wait_queue_head_t queue;
int err;
@@ -3057,14 +3039,13 @@ static int me4000_ai_prepare(me4000_ai_context_t * ai_context)
/* Allocate circular buffer */
ai_context->circ_buf.buf =
- kmalloc(ME4000_AI_BUFFER_SIZE, GFP_KERNEL);
+ kzalloc(ME4000_AI_BUFFER_SIZE, GFP_KERNEL);
if (!ai_context->circ_buf.buf) {
printk(KERN_ERR
"ME4000:me4000_ai_prepare():Can't get circular buffer\n");
free_irq(ai_context->irq, ai_context);
return -ENOMEM;
}
- memset(ai_context->circ_buf.buf, 0, ME4000_AI_BUFFER_SIZE);
/* Clear the circular buffer */
ai_context->circ_buf.head = 0;
@@ -3074,7 +3055,7 @@ static int me4000_ai_prepare(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_reset(me4000_ai_context_t * ai_context)
+static int me4000_ai_reset(struct me4000_ai_context *ai_context)
{
wait_queue_head_t queue;
u32 tmp;
@@ -3139,7 +3120,7 @@ static int me4000_ai_reset(me4000_ai_context_t * ai_context)
static int me4000_ai_ioctl_sing(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
- me4000_ai_context_t *ai_context;
+ struct me4000_ai_context *ai_context;
CALL_PDEBUG("me4000_ai_ioctl_sing() is executed\n");
@@ -3157,16 +3138,17 @@ static int me4000_ai_ioctl_sing(struct inode *inode_p, struct file *file_p,
switch (service) {
case ME4000_AI_SINGLE:
- return me4000_ai_single((me4000_ai_single_t *) arg, ai_context);
+ return me4000_ai_single((struct me4000_ai_single *)arg,
+ ai_context);
case ME4000_AI_EX_TRIG_ENABLE:
return me4000_ai_ex_trig_enable(ai_context);
case ME4000_AI_EX_TRIG_DISABLE:
return me4000_ai_ex_trig_disable(ai_context);
case ME4000_AI_EX_TRIG_SETUP:
- return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg,
+ return me4000_ai_ex_trig_setup((struct me4000_ai_trigger *)arg,
ai_context);
case ME4000_GET_USER_INFO:
- return me4000_get_user_info((me4000_user_info_t *) arg,
+ return me4000_get_user_info((struct me4000_user_info *)arg,
ai_context->board_info);
case ME4000_AI_OFFSET_ENABLE:
return me4000_ai_offset_enable(ai_context);
@@ -3177,9 +3159,11 @@ static int me4000_ai_ioctl_sing(struct inode *inode_p, struct file *file_p,
case ME4000_AI_FULLSCALE_DISABLE:
return me4000_ai_fullscale_disable(ai_context);
case ME4000_AI_EEPROM_READ:
- return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context);
+ return me4000_eeprom_read((struct me4000_eeprom *)arg,
+ ai_context);
case ME4000_AI_EEPROM_WRITE:
- return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context);
+ return me4000_eeprom_write((struct me4000_eeprom *)arg,
+ ai_context);
default:
printk(KERN_ERR
"me4000_ai_ioctl_sing():Invalid service number\n");
@@ -3188,10 +3172,10 @@ static int me4000_ai_ioctl_sing(struct inode *inode_p, struct file *file_p,
return 0;
}
-static int me4000_ai_single(me4000_ai_single_t * arg,
- me4000_ai_context_t * ai_context)
+static int me4000_ai_single(struct me4000_ai_single *arg,
+ struct me4000_ai_context *ai_context)
{
- me4000_ai_single_t cmd;
+ struct me4000_ai_single cmd;
int err;
u32 tmp;
wait_queue_head_t queue;
@@ -3202,7 +3186,7 @@ static int me4000_ai_single(me4000_ai_single_t * arg,
init_waitqueue_head(&queue);
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_ai_single_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_ai_single));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_single():Can't copy from user space\n");
@@ -3301,7 +3285,7 @@ static int me4000_ai_single(me4000_ai_single_t * arg,
cmd.value = me4000_inl(ai_context->data_reg) & 0xFFFF;
/* Copy result back to user */
- err = copy_to_user(arg, &cmd, sizeof(me4000_ai_single_t));
+ err = copy_to_user(arg, &cmd, sizeof(struct me4000_ai_single));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_single():Can't copy to user space\n");
@@ -3314,7 +3298,7 @@ static int me4000_ai_single(me4000_ai_single_t * arg,
static int me4000_ai_ioctl_sw(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
- me4000_ai_context_t *ai_context;
+ struct me4000_ai_context *ai_context;
CALL_PDEBUG("me4000_ai_ioctl_sw() is executed\n");
@@ -3332,9 +3316,11 @@ static int me4000_ai_ioctl_sw(struct inode *inode_p, struct file *file_p,
switch (service) {
case ME4000_AI_SC_SETUP:
- return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context);
+ return me4000_ai_sc_setup((struct me4000_ai_sc *)arg,
+ ai_context);
case ME4000_AI_CONFIG:
- return me4000_ai_config((me4000_ai_config_t *) arg, ai_context);
+ return me4000_ai_config((struct me4000_ai_config *)arg,
+ ai_context);
case ME4000_AI_START:
return me4000_ai_start(ai_context);
case ME4000_AI_STOP:
@@ -3344,19 +3330,20 @@ static int me4000_ai_ioctl_sw(struct inode *inode_p, struct file *file_p,
case ME4000_AI_FSM_STATE:
return me4000_ai_fsm_state((int *)arg, ai_context);
case ME4000_GET_USER_INFO:
- return me4000_get_user_info((me4000_user_info_t *) arg,
+ return me4000_get_user_info((struct me4000_user_info *)arg,
ai_context->board_info);
case ME4000_AI_EEPROM_READ:
- return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context);
+ return me4000_eeprom_read((struct me4000_eeprom *)arg,
+ ai_context);
case ME4000_AI_EEPROM_WRITE:
- return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context);
+ return me4000_eeprom_write((struct me4000_eeprom *)arg,
+ ai_context);
case ME4000_AI_GET_COUNT_BUFFER:
return me4000_ai_get_count_buffer((unsigned long *)arg,
ai_context);
default:
printk(KERN_ERR
- "ME4000:me4000_ai_ioctl_sw():Invalid service number %d\n",
- service);
+ "%s:Invalid service number %d\n", __func__, service);
return -ENOTTY;
}
return 0;
@@ -3365,7 +3352,7 @@ static int me4000_ai_ioctl_sw(struct inode *inode_p, struct file *file_p,
static int me4000_ai_ioctl_ext(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
- me4000_ai_context_t *ai_context;
+ struct me4000_ai_context *ai_context;
CALL_PDEBUG("me4000_ai_ioctl_ext() is executed\n");
@@ -3383,9 +3370,11 @@ static int me4000_ai_ioctl_ext(struct inode *inode_p, struct file *file_p,
switch (service) {
case ME4000_AI_SC_SETUP:
- return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context);
+ return me4000_ai_sc_setup((struct me4000_ai_sc *)arg,
+ ai_context);
case ME4000_AI_CONFIG:
- return me4000_ai_config((me4000_ai_config_t *) arg, ai_context);
+ return me4000_ai_config((struct me4000_ai_config *)arg,
+ ai_context);
case ME4000_AI_START:
return me4000_ai_start_ex((unsigned long *)arg, ai_context);
case ME4000_AI_STOP:
@@ -3397,20 +3386,19 @@ static int me4000_ai_ioctl_ext(struct inode *inode_p, struct file *file_p,
case ME4000_AI_EX_TRIG_DISABLE:
return me4000_ai_ex_trig_disable(ai_context);
case ME4000_AI_EX_TRIG_SETUP:
- return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg,
+ return me4000_ai_ex_trig_setup((struct me4000_ai_trigger *)arg,
ai_context);
case ME4000_AI_FSM_STATE:
return me4000_ai_fsm_state((int *)arg, ai_context);
case ME4000_GET_USER_INFO:
- return me4000_get_user_info((me4000_user_info_t *) arg,
+ return me4000_get_user_info((struct me4000_user_info *)arg,
ai_context->board_info);
case ME4000_AI_GET_COUNT_BUFFER:
return me4000_ai_get_count_buffer((unsigned long *)arg,
ai_context);
default:
printk(KERN_ERR
- "ME4000:me4000_ai_ioctl_ext():Invalid service number %d\n",
- service);
+ "%s:Invalid service number %d\n", __func__ , service);
return -ENOTTY;
}
return 0;
@@ -3418,7 +3406,7 @@ static int me4000_ai_ioctl_ext(struct inode *inode_p, struct file *file_p,
static int me4000_ai_fasync(int fd, struct file *file_p, int mode)
{
- me4000_ai_context_t *ai_context;
+ struct me4000_ai_context *ai_context;
CALL_PDEBUG("me4000_ao_fasync_cont() is executed\n");
@@ -3426,10 +3414,10 @@ static int me4000_ai_fasync(int fd, struct file *file_p, int mode)
return fasync_helper(fd, file_p, mode, &ai_context->fasync_p);
}
-static int me4000_ai_config(me4000_ai_config_t * arg,
- me4000_ai_context_t * ai_context)
+static int me4000_ai_config(struct me4000_ai_config *arg,
+ struct me4000_ai_context *ai_context)
{
- me4000_ai_config_t cmd;
+ struct me4000_ai_config cmd;
u32 *list = NULL;
u32 mode;
int i;
@@ -3451,7 +3439,7 @@ static int me4000_ai_config(me4000_ai_config_t * arg,
}
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_ai_config_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_ai_config));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_config():Can't copy from user space\n");
@@ -3671,7 +3659,7 @@ static int me4000_ai_config(me4000_ai_config_t * arg,
return 0;
- AI_CONFIG_ERR:
+AI_CONFIG_ERR:
/* Reset the timers */
ai_context->chan_timer = 66;
@@ -3699,7 +3687,7 @@ static int me4000_ai_config(me4000_ai_config_t * arg,
}
-static int ai_common_start(me4000_ai_context_t * ai_context)
+static int ai_common_start(struct me4000_ai_context *ai_context)
{
u32 tmp;
CALL_PDEBUG("ai_common_start() is executed\n");
@@ -3762,7 +3750,7 @@ static int ai_common_start(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_start(me4000_ai_context_t * ai_context)
+static int me4000_ai_start(struct me4000_ai_context *ai_context)
{
int err;
CALL_PDEBUG("me4000_ai_start() is executed\n");
@@ -3779,7 +3767,7 @@ static int me4000_ai_start(me4000_ai_context_t * ai_context)
}
static int me4000_ai_start_ex(unsigned long *arg,
- me4000_ai_context_t * ai_context)
+ struct me4000_ai_context *ai_context)
{
int err;
wait_queue_head_t queue;
@@ -3834,7 +3822,7 @@ static int me4000_ai_start_ex(unsigned long *arg,
return 0;
}
-static int me4000_ai_stop(me4000_ai_context_t * ai_context)
+static int me4000_ai_stop(struct me4000_ai_context *ai_context)
{
wait_queue_head_t queue;
u32 tmp;
@@ -3871,7 +3859,7 @@ static int me4000_ai_stop(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_immediate_stop(me4000_ai_context_t * ai_context)
+static int me4000_ai_immediate_stop(struct me4000_ai_context *ai_context)
{
wait_queue_head_t queue;
u32 tmp;
@@ -3908,7 +3896,7 @@ static int me4000_ai_immediate_stop(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_ex_trig_enable(me4000_ai_context_t * ai_context)
+static int me4000_ai_ex_trig_enable(struct me4000_ai_context *ai_context)
{
u32 tmp;
unsigned long flags;
@@ -3924,7 +3912,7 @@ static int me4000_ai_ex_trig_enable(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_ex_trig_disable(me4000_ai_context_t * ai_context)
+static int me4000_ai_ex_trig_disable(struct me4000_ai_context *ai_context)
{
u32 tmp;
unsigned long flags;
@@ -3940,10 +3928,10 @@ static int me4000_ai_ex_trig_disable(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t * arg,
- me4000_ai_context_t * ai_context)
+static int me4000_ai_ex_trig_setup(struct me4000_ai_trigger *arg,
+ struct me4000_ai_context *ai_context)
{
- me4000_ai_trigger_t cmd;
+ struct me4000_ai_trigger cmd;
int err;
u32 tmp;
unsigned long flags;
@@ -3951,7 +3939,7 @@ static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t * arg,
CALL_PDEBUG("me4000_ai_ex_trig_setup() is executed\n");
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_ai_trigger_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_ai_trigger));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_ex_trig_setup():Can't copy from user space\n");
@@ -4000,16 +3988,16 @@ static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t * arg,
return 0;
}
-static int me4000_ai_sc_setup(me4000_ai_sc_t * arg,
- me4000_ai_context_t * ai_context)
+static int me4000_ai_sc_setup(struct me4000_ai_sc *arg,
+ struct me4000_ai_context *ai_context)
{
- me4000_ai_sc_t cmd;
+ struct me4000_ai_sc cmd;
int err;
CALL_PDEBUG("me4000_ai_sc_setup() is executed\n");
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_ai_sc_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_ai_sc));
if (err) {
printk(KERN_ERR
"ME4000:me4000_ai_sc_setup():Can't copy from user space\n");
@@ -4023,9 +4011,9 @@ static int me4000_ai_sc_setup(me4000_ai_sc_t * arg,
}
static ssize_t me4000_ai_read(struct file *filep, char *buff, size_t cnt,
- loff_t * offp)
+ loff_t *offp)
{
- me4000_ai_context_t *ai_context = filep->private_data;
+ struct me4000_ai_context *ai_context = filep->private_data;
s16 *buffer = (s16 *) buff;
size_t count = cnt / 2;
unsigned long flags;
@@ -4150,9 +4138,9 @@ static ssize_t me4000_ai_read(struct file *filep, char *buff, size_t cnt,
return ret * 2;
}
-static unsigned int me4000_ai_poll(struct file *file_p, poll_table * wait)
+static unsigned int me4000_ai_poll(struct file *file_p, poll_table *wait)
{
- me4000_ai_context_t *ai_context;
+ struct me4000_ai_context *ai_context;
unsigned long mask = 0;
CALL_PDEBUG("me4000_ai_poll() is executed\n");
@@ -4171,7 +4159,7 @@ static unsigned int me4000_ai_poll(struct file *file_p, poll_table * wait)
return mask;
}
-static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context)
+static int me4000_ai_offset_enable(struct me4000_ai_context *ai_context)
{
unsigned long tmp;
@@ -4184,7 +4172,7 @@ static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context)
+static int me4000_ai_offset_disable(struct me4000_ai_context *ai_context)
{
unsigned long tmp;
@@ -4197,7 +4185,7 @@ static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context)
+static int me4000_ai_fullscale_enable(struct me4000_ai_context *ai_context)
{
unsigned long tmp;
@@ -4210,7 +4198,7 @@ static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context)
+static int me4000_ai_fullscale_disable(struct me4000_ai_context *ai_context)
{
unsigned long tmp;
@@ -4223,7 +4211,7 @@ static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context)
return 0;
}
-static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context)
+static int me4000_ai_fsm_state(int *arg, struct me4000_ai_context *ai_context)
{
unsigned long tmp;
@@ -4242,7 +4230,7 @@ static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context)
}
static int me4000_ai_get_count_buffer(unsigned long *arg,
- me4000_ai_context_t * ai_context)
+ struct me4000_ai_context *ai_context)
{
unsigned long c;
int err;
@@ -4252,7 +4240,7 @@ static int me4000_ai_get_count_buffer(unsigned long *arg,
err = copy_to_user(arg, &c, sizeof(unsigned long));
if (err) {
printk(KERN_ERR
- "ME4000:me4000_ai_get_count_buffer():Can't copy to user space\n");
+ "%s:Can't copy to user space\n", __func__);
return -EFAULT;
}
@@ -4261,7 +4249,7 @@ static int me4000_ai_get_count_buffer(unsigned long *arg,
/*---------------------------------- EEPROM stuff ---------------------------*/
-static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd,
+static int eeprom_write_cmd(struct me4000_ai_context *ai_context, unsigned long cmd,
int length)
{
int i;
@@ -4318,7 +4306,7 @@ static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd,
return 0;
}
-static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context,
+static unsigned short eeprom_read_cmd(struct me4000_ai_context *ai_context,
unsigned long cmd, int length)
{
int i;
@@ -4397,11 +4385,11 @@ static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context,
return id;
}
-static int me4000_eeprom_write(me4000_eeprom_t * arg,
- me4000_ai_context_t * ai_context)
+static int me4000_eeprom_write(struct me4000_eeprom *arg,
+ struct me4000_ai_context *ai_context)
{
int err;
- me4000_eeprom_t setup;
+ struct me4000_eeprom setup;
unsigned long cmd;
unsigned long date_high;
unsigned long date_low;
@@ -4594,12 +4582,12 @@ static int me4000_eeprom_write(me4000_eeprom_t * arg,
return 0;
}
-static int me4000_eeprom_read(me4000_eeprom_t * arg,
- me4000_ai_context_t * ai_context)
+static int me4000_eeprom_read(struct me4000_eeprom *arg,
+ struct me4000_ai_context *ai_context)
{
int err;
unsigned long cmd;
- me4000_eeprom_t setup;
+ struct me4000_eeprom setup;
CALL_PDEBUG("me4000_eeprom_read() is executed\n");
@@ -4687,7 +4675,7 @@ static int me4000_eeprom_read(me4000_eeprom_t * arg,
static int me4000_dio_ioctl(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
- me4000_dio_context_t *dio_context;
+ struct me4000_dio_context *dio_context;
CALL_PDEBUG("me4000_dio_ioctl() is executed\n");
@@ -4704,13 +4692,13 @@ static int me4000_dio_ioctl(struct inode *inode_p, struct file *file_p,
switch (service) {
case ME4000_DIO_CONFIG:
- return me4000_dio_config((me4000_dio_config_t *) arg,
+ return me4000_dio_config((struct me4000_dio_config *)arg,
dio_context);
case ME4000_DIO_SET_BYTE:
- return me4000_dio_set_byte((me4000_dio_byte_t *) arg,
+ return me4000_dio_set_byte((struct me4000_dio_byte *)arg,
dio_context);
case ME4000_DIO_GET_BYTE:
- return me4000_dio_get_byte((me4000_dio_byte_t *) arg,
+ return me4000_dio_get_byte((struct me4000_dio_byte *)arg,
dio_context);
case ME4000_DIO_RESET:
return me4000_dio_reset(dio_context);
@@ -4723,17 +4711,17 @@ static int me4000_dio_ioctl(struct inode *inode_p, struct file *file_p,
return 0;
}
-static int me4000_dio_config(me4000_dio_config_t * arg,
- me4000_dio_context_t * dio_context)
+static int me4000_dio_config(struct me4000_dio_config *arg,
+ struct me4000_dio_context *dio_context)
{
- me4000_dio_config_t cmd;
+ struct me4000_dio_config cmd;
u32 tmp;
int err;
CALL_PDEBUG("me4000_dio_config() is executed\n");
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_dio_config_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_dio_config));
if (err) {
printk(KERN_ERR
"ME4000:me4000_dio_config():Can't copy from user space\n");
@@ -4964,16 +4952,16 @@ static int me4000_dio_config(me4000_dio_config_t * arg,
return 0;
}
-static int me4000_dio_set_byte(me4000_dio_byte_t * arg,
- me4000_dio_context_t * dio_context)
+static int me4000_dio_set_byte(struct me4000_dio_byte *arg,
+ struct me4000_dio_context *dio_context)
{
- me4000_dio_byte_t cmd;
+ struct me4000_dio_byte cmd;
int err;
CALL_PDEBUG("me4000_dio_set_byte() is executed\n");
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_dio_byte));
if (err) {
printk(KERN_ERR
"ME4000:me4000_dio_set_byte():Can't copy from user space\n");
@@ -5030,16 +5018,16 @@ static int me4000_dio_set_byte(me4000_dio_byte_t * arg,
return 0;
}
-static int me4000_dio_get_byte(me4000_dio_byte_t * arg,
- me4000_dio_context_t * dio_context)
+static int me4000_dio_get_byte(struct me4000_dio_byte *arg,
+ struct me4000_dio_context *dio_context)
{
- me4000_dio_byte_t cmd;
+ struct me4000_dio_byte cmd;
int err;
CALL_PDEBUG("me4000_dio_get_byte() is executed\n");
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_dio_byte));
if (err) {
printk(KERN_ERR
"ME4000:me4000_dio_get_byte():Can't copy from user space\n");
@@ -5070,7 +5058,7 @@ static int me4000_dio_get_byte(me4000_dio_byte_t * arg,
}
/* Copy result back to user */
- err = copy_to_user(arg, &cmd, sizeof(me4000_dio_byte_t));
+ err = copy_to_user(arg, &cmd, sizeof(struct me4000_dio_byte));
if (err) {
printk(KERN_ERR
"ME4000:me4000_dio_get_byte():Can't copy to user space\n");
@@ -5080,7 +5068,7 @@ static int me4000_dio_get_byte(me4000_dio_byte_t * arg,
return 0;
}
-static int me4000_dio_reset(me4000_dio_context_t * dio_context)
+static int me4000_dio_reset(struct me4000_dio_context *dio_context)
{
CALL_PDEBUG("me4000_dio_reset() is executed\n");
@@ -5101,7 +5089,7 @@ static int me4000_dio_reset(me4000_dio_context_t * dio_context)
static int me4000_cnt_ioctl(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
- me4000_cnt_context_t *cnt_context;
+ struct me4000_cnt_context *cnt_context;
CALL_PDEBUG("me4000_cnt_ioctl() is executed\n");
@@ -5118,11 +5106,11 @@ static int me4000_cnt_ioctl(struct inode *inode_p, struct file *file_p,
switch (service) {
case ME4000_CNT_READ:
- return me4000_cnt_read((me4000_cnt_t *) arg, cnt_context);
+ return me4000_cnt_read((struct me4000_cnt *)arg, cnt_context);
case ME4000_CNT_WRITE:
- return me4000_cnt_write((me4000_cnt_t *) arg, cnt_context);
+ return me4000_cnt_write((struct me4000_cnt *)arg, cnt_context);
case ME4000_CNT_CONFIG:
- return me4000_cnt_config((me4000_cnt_config_t *) arg,
+ return me4000_cnt_config((struct me4000_cnt_config *)arg,
cnt_context);
case ME4000_CNT_RESET:
return me4000_cnt_reset(cnt_context);
@@ -5135,10 +5123,10 @@ static int me4000_cnt_ioctl(struct inode *inode_p, struct file *file_p,
return 0;
}
-static int me4000_cnt_config(me4000_cnt_config_t * arg,
- me4000_cnt_context_t * cnt_context)
+static int me4000_cnt_config(struct me4000_cnt_config *arg,
+ struct me4000_cnt_context *cnt_context)
{
- me4000_cnt_config_t cmd;
+ struct me4000_cnt_config cmd;
u8 counter;
u8 mode;
int err;
@@ -5146,7 +5134,7 @@ static int me4000_cnt_config(me4000_cnt_config_t * arg,
CALL_PDEBUG("me4000_cnt_config() is executed\n");
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_config_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_cnt_config));
if (err) {
printk(KERN_ERR
"ME4000:me4000_cnt_config():Can't copy from user space\n");
@@ -5204,17 +5192,17 @@ static int me4000_cnt_config(me4000_cnt_config_t * arg,
return 0;
}
-static int me4000_cnt_read(me4000_cnt_t * arg,
- me4000_cnt_context_t * cnt_context)
+static int me4000_cnt_read(struct me4000_cnt *arg,
+ struct me4000_cnt_context *cnt_context)
{
- me4000_cnt_t cmd;
+ struct me4000_cnt cmd;
u8 tmp;
int err;
CALL_PDEBUG("me4000_cnt_read() is executed\n");
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_cnt));
if (err) {
printk(KERN_ERR
"ME4000:me4000_cnt_read():Can't copy from user space\n");
@@ -5249,7 +5237,7 @@ static int me4000_cnt_read(me4000_cnt_t * arg,
}
/* Copy result back to user */
- err = copy_to_user(arg, &cmd, sizeof(me4000_cnt_t));
+ err = copy_to_user(arg, &cmd, sizeof(struct me4000_cnt));
if (err) {
printk(KERN_ERR
"ME4000:me4000_cnt_read():Can't copy to user space\n");
@@ -5259,17 +5247,17 @@ static int me4000_cnt_read(me4000_cnt_t * arg,
return 0;
}
-static int me4000_cnt_write(me4000_cnt_t * arg,
- me4000_cnt_context_t * cnt_context)
+static int me4000_cnt_write(struct me4000_cnt *arg,
+ struct me4000_cnt_context *cnt_context)
{
- me4000_cnt_t cmd;
+ struct me4000_cnt cmd;
u8 tmp;
int err;
CALL_PDEBUG("me4000_cnt_write() is executed\n");
/* Copy data from user */
- err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t));
+ err = copy_from_user(&cmd, arg, sizeof(struct me4000_cnt));
if (err) {
printk(KERN_ERR
"ME4000:me4000_cnt_write():Can't copy from user space\n");
@@ -5306,7 +5294,7 @@ static int me4000_cnt_write(me4000_cnt_t * arg,
return 0;
}
-static int me4000_cnt_reset(me4000_cnt_context_t * cnt_context)
+static int me4000_cnt_reset(struct me4000_cnt_context *cnt_context)
{
CALL_PDEBUG("me4000_cnt_reset() is executed\n");
@@ -5333,7 +5321,7 @@ static int me4000_cnt_reset(me4000_cnt_context_t * cnt_context)
static int me4000_ext_int_ioctl(struct inode *inode_p, struct file *file_p,
unsigned int service, unsigned long arg)
{
- me4000_ext_int_context_t *ext_int_context;
+ struct me4000_ext_int_context *ext_int_context;
CALL_PDEBUG("me4000_ext_int_ioctl() is executed\n");
@@ -5366,7 +5354,7 @@ static int me4000_ext_int_ioctl(struct inode *inode_p, struct file *file_p,
return 0;
}
-static int me4000_ext_int_enable(me4000_ext_int_context_t * ext_int_context)
+static int me4000_ext_int_enable(struct me4000_ext_int_context *ext_int_context)
{
unsigned long tmp;
@@ -5379,7 +5367,7 @@ static int me4000_ext_int_enable(me4000_ext_int_context_t * ext_int_context)
return 0;
}
-static int me4000_ext_int_disable(me4000_ext_int_context_t * ext_int_context)
+static int me4000_ext_int_disable(struct me4000_ext_int_context *ext_int_context)
{
unsigned long tmp;
@@ -5393,7 +5381,7 @@ static int me4000_ext_int_disable(me4000_ext_int_context_t * ext_int_context)
}
static int me4000_ext_int_count(unsigned long *arg,
- me4000_ext_int_context_t * ext_int_context)
+ struct me4000_ext_int_context *ext_int_context)
{
CALL_PDEBUG("me4000_ext_int_count() is executed\n");
@@ -5404,10 +5392,10 @@ static int me4000_ext_int_count(unsigned long *arg,
/*------------------------------------ General stuff ------------------------------------*/
-static int me4000_get_user_info(me4000_user_info_t * arg,
- me4000_info_t * board_info)
+static int me4000_get_user_info(struct me4000_user_info *arg,
+ struct me4000_info *board_info)
{
- me4000_user_info_t user_info;
+ struct me4000_user_info user_info;
CALL_PDEBUG("me4000_get_user_info() is executed\n");
@@ -5437,7 +5425,7 @@ static int me4000_get_user_info(me4000_user_info_t * arg,
user_info.cnt_count = board_info->board_p->cnt.count;
- if (copy_to_user(arg, &user_info, sizeof(me4000_user_info_t)))
+ if (copy_to_user(arg, &user_info, sizeof(struct me4000_user_info)))
return -EFAULT;
return 0;
@@ -5448,7 +5436,7 @@ static int me4000_get_user_info(me4000_user_info_t * arg,
static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode)
{
int result = 0;
- me4000_ext_int_context_t *ext_int_context;
+ struct me4000_ext_int_context *ext_int_context;
CALL_PDEBUG("me4000_ext_int_fasync() is executed\n");
@@ -5465,7 +5453,7 @@ static irqreturn_t me4000_ao_isr(int irq, void *dev_id)
{
u32 tmp;
u32 value;
- me4000_ao_context_t *ao_context;
+ struct me4000_ao_context *ao_context;
int i;
int c = 0;
int c1 = 0;
@@ -5589,7 +5577,7 @@ static irqreturn_t me4000_ao_isr(int irq, void *dev_id)
static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
{
u32 tmp;
- me4000_ai_context_t *ai_context;
+ struct me4000_ai_context *ai_context;
int i;
int c = 0;
int c1 = 0;
@@ -5933,7 +5921,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
static irqreturn_t me4000_ext_int_isr(int irq, void *dev_id)
{
- me4000_ext_int_context_t *ext_int_context;
+ struct me4000_ext_int_context *ext_int_context;
unsigned long tmp;
ISR_PDEBUG("me4000_ext_int_isr() is executed\n");
@@ -5969,10 +5957,10 @@ static irqreturn_t me4000_ext_int_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-void __exit me4000_module_exit(void)
+static void __exit me4000_module_exit(void)
{
struct list_head *board_p;
- me4000_info_t *board_info;
+ struct me4000_info *board_info;
CALL_PDEBUG("cleanup_module() is executed\n");
@@ -5993,7 +5981,7 @@ void __exit me4000_module_exit(void)
/* Reset the boards */
for (board_p = me4000_board_info_list.next;
board_p != &me4000_board_info_list; board_p = board_p->next) {
- board_info = list_entry(board_p, me4000_info_t, list);
+ board_info = list_entry(board_p, struct me4000_info, list);
me4000_reset_board(board_info);
}
@@ -6007,7 +5995,7 @@ static int me4000_read_procmem(char *buf, char **start, off_t offset, int count,
{
int len = 0;
int limit = count - 1000;
- me4000_info_t *board_info;
+ struct me4000_info *board_info;
struct list_head *ptr;
len += sprintf(buf + len, "\nME4000 DRIVER VERSION %X.%X.%X\n\n",
@@ -6019,7 +6007,7 @@ static int me4000_read_procmem(char *buf, char **start, off_t offset, int count,
for (ptr = me4000_board_info_list.next;
(ptr != &me4000_board_info_list) && (len < limit);
ptr = ptr->next) {
- board_info = list_entry(ptr, me4000_info_t, list);
+ board_info = list_entry(ptr, struct me4000_info, list);
len +=
sprintf(buf + len, "Board number %d:\n",
@@ -6029,14 +6017,14 @@ static int me4000_read_procmem(char *buf, char **start, off_t offset, int count,
sprintf(buf + len, "PLX base register = 0x%lX\n",
board_info->plx_regbase);
len +=
- sprintf(buf + len, "PLX base register size = 0x%lX\n",
- board_info->plx_regbase_size);
+ sprintf(buf + len, "PLX base register size = 0x%X\n",
+ (unsigned int)board_info->plx_regbase_size);
len +=
- sprintf(buf + len, "ME4000 base register = 0x%lX\n",
- board_info->me4000_regbase);
+ sprintf(buf + len, "ME4000 base register = 0x%X\n",
+ (unsigned int)board_info->me4000_regbase);
len +=
- sprintf(buf + len, "ME4000 base register size = 0x%lX\n",
- board_info->me4000_regbase_size);
+ sprintf(buf + len, "ME4000 base register size = 0x%X\n",
+ (unsigned int)board_info->me4000_regbase_size);
len +=
sprintf(buf + len, "Serial number = 0x%X\n",
board_info->serial_no);
diff --git a/drivers/staging/me4000/me4000.h b/drivers/staging/me4000/me4000.h
index c35e4b9793a..81c6f4d5e25 100644
--- a/drivers/staging/me4000/me4000.h
+++ b/drivers/staging/me4000/me4000.h
@@ -329,46 +329,46 @@
Circular buffer used for analog input/output reads/writes.
===========================================================================*/
-typedef struct me4000_circ_buf {
+struct me4000_circ_buf {
s16 *buf;
int volatile head;
int volatile tail;
-} me4000_circ_buf_t;
+};
/*=============================================================================
Information about the hardware capabilities
===========================================================================*/
-typedef struct me4000_ao_info {
+struct me4000_ao_info {
int count;
int fifo_count;
-} me4000_ao_info_t;
+};
-typedef struct me4000_ai_info {
+struct me4000_ai_info {
int count;
int sh_count;
int diff_count;
int ex_trig_analog;
-} me4000_ai_info_t;
+};
-typedef struct me4000_dio_info {
+struct me4000_dio_info {
int count;
-} me4000_dio_info_t;
+};
-typedef struct me4000_cnt_info {
+struct me4000_cnt_info {
int count;
-} me4000_cnt_info_t;
+};
-typedef struct me4000_board {
+struct me4000_board {
u16 vendor_id;
u16 device_id;
- me4000_ao_info_t ao;
- me4000_ai_info_t ai;
- me4000_dio_info_t dio;
- me4000_cnt_info_t cnt;
-} me4000_board_t;
+ struct me4000_ao_info ao;
+ struct me4000_ai_info ai;
+ struct me4000_dio_info dio;
+ struct me4000_cnt_info cnt;
+};
-static me4000_board_t me4000_boards[] = {
+static struct me4000_board me4000_boards[] = {
{PCI_VENDOR_ID_MEILHAUS, 0x4610, {0, 0}, {16, 0, 0, 0}, {4}, {3}},
{PCI_VENDOR_ID_MEILHAUS, 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0}},
@@ -391,8 +391,6 @@ static me4000_board_t me4000_boards[] = {
{0},
};
-#define ME4000_BOARD_VERSIONS (sizeof(me4000_boards) / sizeof(me4000_board_t) - 1)
-
/*=============================================================================
PCI device table.
This is used by modprobe to translate PCI IDs to drivers.
@@ -427,19 +425,19 @@ MODULE_DEVICE_TABLE(pci, me4000_pci_table);
Global board and subdevice information structures
===========================================================================*/
-typedef struct me4000_info {
+struct me4000_info {
struct list_head list; // List of all detected boards
int board_count; // Index of the board after detection
unsigned long plx_regbase; // PLX configuration space base address
- unsigned long me4000_regbase; // Base address of the ME4000
- unsigned long timer_regbase; // Base address of the timer circuit
- unsigned long program_regbase; // Base address to set the program pin for the xilinx
+ resource_size_t me4000_regbase; // Base address of the ME4000
+ resource_size_t timer_regbase; // Base address of the timer circuit
+ resource_size_t program_regbase; // Base address to set the program pin for the xilinx
unsigned long plx_regbase_size; // PLX register set space
- unsigned long me4000_regbase_size; // ME4000 register set space
- unsigned long timer_regbase_size; // Timer circuit register set space
- unsigned long program_regbase_size; // Size of program base address of the ME4000
+ resource_size_t me4000_regbase_size; // ME4000 register set space
+ resource_size_t timer_regbase_size; // Timer circuit register set space
+ resource_size_t program_regbase_size; // Size of program base address of the ME4000
unsigned int serial_no; // Serial number of the board
unsigned char hw_revision; // Hardware revision of the board
@@ -451,7 +449,7 @@ typedef struct me4000_info {
int pci_func_no; // PCI function number
struct pci_dev *pci_dev_p; // General PCI information
- me4000_board_t *board_p; // Holds the board capabilities
+ struct me4000_board *board_p; // Holds the board capabilities
unsigned int irq; // IRQ assigned from the PCI BIOS
unsigned int irq_count; // Count of external interrupts
@@ -464,18 +462,18 @@ typedef struct me4000_info {
struct me4000_dio_context *dio_context; // Digital I/O specific context
struct me4000_cnt_context *cnt_context; // Counter specific context
struct me4000_ext_int_context *ext_int_context; // External interrupt specific context
-} me4000_info_t;
+};
-typedef struct me4000_ao_context {
+struct me4000_ao_context {
struct list_head list; // linked list of me4000_ao_context_t
int index; // Index in the list
int mode; // Indicates mode (0 = single, 1 = wraparound, 2 = continous)
int dac_in_use; // Indicates if already opend
spinlock_t use_lock; // Guards in_use
spinlock_t int_lock; // Used when locking out interrupts
- me4000_circ_buf_t circ_buf; // Circular buffer
+ struct me4000_circ_buf circ_buf; // Circular buffer
wait_queue_head_t wait_queue; // Wait queue to sleep while blocking write
- me4000_info_t *board_info;
+ struct me4000_info *board_info;
unsigned int irq; // The irq associated with this ADC
int volatile pipe_flag; // Indicates broken pipe set from me4000_ao_isr()
unsigned long ctrl_reg;
@@ -486,9 +484,9 @@ typedef struct me4000_ao_context {
unsigned long irq_status_reg;
unsigned long preload_reg;
struct fasync_struct *fasync_p; // Queue for asynchronous notification
-} me4000_ao_context_t;
+};
-typedef struct me4000_ai_context {
+struct me4000_ai_context {
struct list_head list; // linked list of me4000_ai_info_t
int mode; // Indicates mode
int in_use; // Indicates if already opend
@@ -496,9 +494,9 @@ typedef struct me4000_ai_context {
spinlock_t int_lock; // Used when locking out interrupts
int number; // Number of the DAC
unsigned int irq; // The irq associated with this ADC
- me4000_circ_buf_t circ_buf; // Circular buffer
+ struct me4000_circ_buf circ_buf; // Circular buffer
wait_queue_head_t wait_queue; // Wait queue to sleep while blocking read
- me4000_info_t *board_info;
+ struct me4000_info *board_info;
struct fasync_struct *fasync_p; // Queue for asynchronous notification
@@ -523,48 +521,48 @@ typedef struct me4000_ai_context {
unsigned long channel_list_count;
unsigned long sample_counter;
int sample_counter_reload;
-} me4000_ai_context_t;
+};
-typedef struct me4000_dio_context {
+struct me4000_dio_context {
struct list_head list; // linked list of me4000_dio_context_t
int in_use; // Indicates if already opend
spinlock_t use_lock; // Guards in_use
int number;
int dio_count;
- me4000_info_t *board_info;
+ struct me4000_info *board_info;
unsigned long dir_reg;
unsigned long ctrl_reg;
unsigned long port_0_reg;
unsigned long port_1_reg;
unsigned long port_2_reg;
unsigned long port_3_reg;
-} me4000_dio_context_t;
+};
-typedef struct me4000_cnt_context {
+struct me4000_cnt_context {
struct list_head list; // linked list of me4000_dio_context_t
int in_use; // Indicates if already opend
spinlock_t use_lock; // Guards in_use
int number;
int cnt_count;
- me4000_info_t *board_info;
+ struct me4000_info *board_info;
unsigned long ctrl_reg;
unsigned long counter_0_reg;
unsigned long counter_1_reg;
unsigned long counter_2_reg;
-} me4000_cnt_context_t;
+};
-typedef struct me4000_ext_int_context {
+struct me4000_ext_int_context {
struct list_head list; // linked list of me4000_dio_context_t
int in_use; // Indicates if already opend
spinlock_t use_lock; // Guards in_use
int number;
- me4000_info_t *board_info;
+ struct me4000_info *board_info;
unsigned int irq;
unsigned long int_count;
struct fasync_struct *fasync_ptr;
unsigned long ctrl_reg;
unsigned long irq_status_reg;
-} me4000_ext_int_context_t;
+};
#endif
@@ -745,12 +743,12 @@ typedef struct me4000_ext_int_context {
General type definitions
----------------------------------------------------------------------------*/
-typedef struct me4000_user_info {
+struct me4000_user_info {
int board_count; // Index of the board after detection
unsigned long plx_regbase; // PLX configuration space base address
- unsigned long me4000_regbase; // Base address of the ME4000
+ resource_size_t me4000_regbase; // Base address of the ME4000
unsigned long plx_regbase_size; // PLX register set space
- unsigned long me4000_regbase_size; // ME4000 register set space
+ resource_size_t me4000_regbase_size; // ME4000 register set space
unsigned long serial_no; // Serial number of the board
unsigned char hw_revision; // Hardware revision of the board
unsigned short vendor_id; // Meilhaus vendor id (0x1402)
@@ -773,62 +771,62 @@ typedef struct me4000_user_info {
int dio_count; // Count of digital I/O ports
int cnt_count; // Count of counters
-} me4000_user_info_t;
+};
/*-----------------------------------------------------------------------------
Type definitions for analog output
----------------------------------------------------------------------------*/
-typedef struct me4000_ao_channel_list {
+struct me4000_ao_channel_list {
unsigned long count;
unsigned long *list;
-} me4000_ao_channel_list_t;
+};
/*-----------------------------------------------------------------------------
Type definitions for analog input
----------------------------------------------------------------------------*/
-typedef struct me4000_ai_channel_list {
+struct me4000_ai_channel_list {
unsigned long count;
unsigned long *list;
-} me4000_ai_channel_list_t;
+};
-typedef struct me4000_ai_timer {
+struct me4000_ai_timer {
unsigned long pre_chan;
unsigned long chan;
unsigned long scan_low;
unsigned long scan_high;
-} me4000_ai_timer_t;
+};
-typedef struct me4000_ai_config {
- me4000_ai_timer_t timer;
- me4000_ai_channel_list_t channel_list;
+struct me4000_ai_config {
+ struct me4000_ai_timer timer;
+ struct me4000_ai_channel_list channel_list;
int sh;
-} me4000_ai_config_t;
+};
-typedef struct me4000_ai_single {
+struct me4000_ai_single {
int channel;
int range;
int mode;
short value;
unsigned long timeout;
-} me4000_ai_single_t;
+};
-typedef struct me4000_ai_trigger {
+struct me4000_ai_trigger {
int mode;
int edge;
-} me4000_ai_trigger_t;
+};
-typedef struct me4000_ai_sc {
+struct me4000_ai_sc {
unsigned long value;
int reload;
-} me4000_ai_sc_t;
+};
/*-----------------------------------------------------------------------------
Type definitions for eeprom
----------------------------------------------------------------------------*/
-typedef struct me4000_eeprom {
+struct me4000_eeprom {
unsigned long date;
short uni_10_offset;
short uni_10_fullscale;
@@ -842,45 +840,45 @@ typedef struct me4000_eeprom {
short diff_10_fullscale;
short diff_2_5_offset;
short diff_2_5_fullscale;
-} me4000_eeprom_t;
+};
/*-----------------------------------------------------------------------------
Type definitions for digital I/O
----------------------------------------------------------------------------*/
-typedef struct me4000_dio_config {
+struct me4000_dio_config {
int port;
int mode;
int function;
-} me4000_dio_config_t;
+};
-typedef struct me4000_dio_byte {
+struct me4000_dio_byte {
int port;
unsigned char byte;
-} me4000_dio_byte_t;
+};
/*-----------------------------------------------------------------------------
Type definitions for counters
----------------------------------------------------------------------------*/
-typedef struct me4000_cnt {
+struct me4000_cnt {
int counter;
unsigned short value;
-} me4000_cnt_t;
+};
-typedef struct me4000_cnt_config {
+struct me4000_cnt_config {
int counter;
int mode;
-} me4000_cnt_config_t;
+};
/*-----------------------------------------------------------------------------
Type definitions for external interrupt
----------------------------------------------------------------------------*/
-typedef struct {
+struct me4000_int {
int int1_count;
int int2_count;
-} me4000_int_type;
+};
/*-----------------------------------------------------------------------------
The ioctls of the board
@@ -888,7 +886,8 @@ typedef struct {
#define ME4000_IOCTL_MAXNR 50
#define ME4000_MAGIC 'y'
-#define ME4000_GET_USER_INFO _IOR (ME4000_MAGIC, 0, me4000_user_info_t)
+#define ME4000_GET_USER_INFO _IOR (ME4000_MAGIC, 0, \
+ struct me4000_user_info)
#define ME4000_AO_START _IOW (ME4000_MAGIC, 1, unsigned long)
#define ME4000_AO_STOP _IO (ME4000_MAGIC, 2)
@@ -904,25 +903,35 @@ typedef struct {
#define ME4000_AO_DISABLE_DO _IO (ME4000_MAGIC, 12)
#define ME4000_AO_FSM_STATE _IOR (ME4000_MAGIC, 13, int)
-#define ME4000_AI_SINGLE _IOR (ME4000_MAGIC, 14, me4000_ai_single_t)
+#define ME4000_AI_SINGLE _IOR (ME4000_MAGIC, 14, \
+ struct me4000_ai_single)
#define ME4000_AI_START _IOW (ME4000_MAGIC, 15, unsigned long)
#define ME4000_AI_STOP _IO (ME4000_MAGIC, 16)
#define ME4000_AI_IMMEDIATE_STOP _IO (ME4000_MAGIC, 17)
#define ME4000_AI_EX_TRIG_ENABLE _IO (ME4000_MAGIC, 18)
#define ME4000_AI_EX_TRIG_DISABLE _IO (ME4000_MAGIC, 19)
-#define ME4000_AI_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 20, me4000_ai_trigger_t)
-#define ME4000_AI_CONFIG _IOW (ME4000_MAGIC, 21, me4000_ai_config_t)
-#define ME4000_AI_SC_SETUP _IOW (ME4000_MAGIC, 22, me4000_ai_sc_t)
+#define ME4000_AI_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 20, \
+ struct me4000_ai_trigger)
+#define ME4000_AI_CONFIG _IOW (ME4000_MAGIC, 21, \
+ struct me4000_ai_config)
+#define ME4000_AI_SC_SETUP _IOW (ME4000_MAGIC, 22, \
+ struct me4000_ai_sc)
#define ME4000_AI_FSM_STATE _IOR (ME4000_MAGIC, 23, int)
-#define ME4000_DIO_CONFIG _IOW (ME4000_MAGIC, 24, me4000_dio_config_t)
-#define ME4000_DIO_GET_BYTE _IOR (ME4000_MAGIC, 25, me4000_dio_byte_t)
-#define ME4000_DIO_SET_BYTE _IOW (ME4000_MAGIC, 26, me4000_dio_byte_t)
+#define ME4000_DIO_CONFIG _IOW (ME4000_MAGIC, 24, \
+ struct me4000_dio_config)
+#define ME4000_DIO_GET_BYTE _IOR (ME4000_MAGIC, 25, \
+ struct me4000_dio_byte)
+#define ME4000_DIO_SET_BYTE _IOW (ME4000_MAGIC, 26, \
+ struct me4000_dio_byte)
#define ME4000_DIO_RESET _IO (ME4000_MAGIC, 27)
-#define ME4000_CNT_READ _IOR (ME4000_MAGIC, 28, me4000_cnt_t)
-#define ME4000_CNT_WRITE _IOW (ME4000_MAGIC, 29, me4000_cnt_t)
-#define ME4000_CNT_CONFIG _IOW (ME4000_MAGIC, 30, me4000_cnt_config_t)
+#define ME4000_CNT_READ _IOR (ME4000_MAGIC, 28, \
+ struct me4000_cnt)
+#define ME4000_CNT_WRITE _IOW (ME4000_MAGIC, 29, \
+ struct me4000_cnt)
+#define ME4000_CNT_CONFIG _IOW (ME4000_MAGIC, 30, \
+ struct me4000_cnt_config)
#define ME4000_CNT_RESET _IO (ME4000_MAGIC, 31)
#define ME4000_EXT_INT_DISABLE _IO (ME4000_MAGIC, 32)
@@ -934,13 +943,16 @@ typedef struct {
#define ME4000_AI_FULLSCALE_ENABLE _IO (ME4000_MAGIC, 37)
#define ME4000_AI_FULLSCALE_DISABLE _IO (ME4000_MAGIC, 38)
-#define ME4000_AI_EEPROM_READ _IOR (ME4000_MAGIC, 39, me4000_eeprom_t)
-#define ME4000_AI_EEPROM_WRITE _IOW (ME4000_MAGIC, 40, me4000_eeprom_t)
+#define ME4000_AI_EEPROM_READ _IOR (ME4000_MAGIC, 39, \
+ struct me4000_eeprom)
+#define ME4000_AI_EEPROM_WRITE _IOW (ME4000_MAGIC, 40, \
+ struct me4000_eeprom)
#define ME4000_AO_SIMULTANEOUS_EX_TRIG _IO (ME4000_MAGIC, 41)
#define ME4000_AO_SIMULTANEOUS_SW _IO (ME4000_MAGIC, 42)
#define ME4000_AO_SIMULTANEOUS_DISABLE _IO (ME4000_MAGIC, 43)
-#define ME4000_AO_SIMULTANEOUS_UPDATE _IOW (ME4000_MAGIC, 44, me4000_ao_channel_list_t)
+#define ME4000_AO_SIMULTANEOUS_UPDATE _IOW (ME4000_MAGIC, 44, \
+ struct me4000_ao_channel_list)
#define ME4000_AO_SYNCHRONOUS_EX_TRIG _IO (ME4000_MAGIC, 45)
#define ME4000_AO_SYNCHRONOUS_SW _IO (ME4000_MAGIC, 46)
diff --git a/drivers/staging/pcc-acpi/Kconfig b/drivers/staging/pcc-acpi/Kconfig
new file mode 100644
index 00000000000..6720d4086ba
--- /dev/null
+++ b/drivers/staging/pcc-acpi/Kconfig
@@ -0,0 +1,11 @@
+config PCC_ACPI
+ tristate "Panasonic ACPI Hotkey support"
+ depends on ACPI
+ default n
+ ---help---
+ This driver provides support for Panasonic hotkeys through the
+ ACPI interface. This works for the Panasonic R1 (N variant),
+ R2, R3, T2, W2, and Y2 laptops.
+
+ To compile this driver as a module, choose M here. The module
+ will be called pcc-acpi.
diff --git a/drivers/staging/pcc-acpi/Makefile b/drivers/staging/pcc-acpi/Makefile
new file mode 100644
index 00000000000..f93b29edf61
--- /dev/null
+++ b/drivers/staging/pcc-acpi/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PCC_ACPI) += pcc-acpi.o
diff --git a/drivers/staging/pcc-acpi/TODO b/drivers/staging/pcc-acpi/TODO
new file mode 100644
index 00000000000..fab24098228
--- /dev/null
+++ b/drivers/staging/pcc-acpi/TODO
@@ -0,0 +1,7 @@
+TODO:
+ - Lindent fixes
+ - checkpatch.pl fixes
+ - verify that the acpi interface is correct
+ - remove /proc dependancy if needed (not sure yet.)
+
+Please send any patches for this driver to Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/pcc-acpi/pcc-acpi.c b/drivers/staging/pcc-acpi/pcc-acpi.c
new file mode 100644
index 00000000000..3b34a3e4885
--- /dev/null
+++ b/drivers/staging/pcc-acpi/pcc-acpi.c
@@ -0,0 +1,1111 @@
+/*
+ * Panasonic HotKey and lcd brightness control Extra driver
+ * (C) 2004 Hiroshi Miura <miura@da-cha.org>
+ * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
+ * (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp>
+ * (C) 2004 David Bronaugh <dbronaugh>
+ *
+ * derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte
+ *
+ * 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
+ * publicshed 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *---------------------------------------------------------------------------
+ *
+ * ChangeLog:
+ *
+ * Nov.04, 2006 Hiroshi Miura <miura@da-cha.org>
+ * -v0.9 remove warning about section reference.
+ * remove acpi_os_free
+ * add /proc/acpi/pcc/brightness interface to
+ * allow HAL to access.
+ * merge dbronaugh's enhancement
+ * Aug.17, 2004 David Bronaugh (dbronaugh)
+ * - Added screen brightness setting interface
+ * Thanks to the FreeBSD crew
+ * (acpi_panasonic.c authors)
+ * for the ideas I needed to accomplish it
+ *
+ * May.29, 2006 Hiroshi Miura <miura@da-cha.org>
+ * -v0.8.4 follow to change keyinput structure
+ * thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>,
+ * Jacob Bower <jacob.bower@ic.ac.uk> and
+ * Hiroshi Yokota for providing solutions.
+ *
+ * Oct.02, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.8.2 merge code of YOKOTA Hiroshi
+ * <yokota@netlab.is.tsukuba.ac.jp>.
+ * Add sticky key mode interface.
+ * Refactoring acpi_pcc_generete_keyinput().
+ *
+ * Sep.15, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.8 Generate key input event on input subsystem.
+ * This is based on yet another driver
+ * written by Ryuta Nakanishi.
+ *
+ * Sep.10, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.7 Change proc interface functions using seq_file
+ * facility as same as other ACPI drivers.
+ *
+ * Aug.28, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.6.4 Fix a silly error with status checking
+ *
+ * Aug.25, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.6.3 replace read_acpi_int by standard
+ * function acpi_evaluate_integer
+ * some clean up and make smart copyright notice.
+ * fix return value of pcc_acpi_get_key()
+ * fix checking return value of acpi_bus_register_driver()
+ *
+ * Aug.22, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * -v0.6.2 Add check on ACPI data (num_sifr)
+ * Coding style cleanups, better error messages/handling
+ * Fixed an off-by-one error in memory allocation
+ *
+ * Aug.21, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * -v0.6.1 Fix a silly error with status checking
+ *
+ * Aug.20, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * - v0.6 Correct brightness controls to reflect reality
+ * based on information gleaned by Hiroshi Miura
+ * and discussions with Hiroshi Miura
+ *
+ * Aug.10, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.5 support LCD brightness control
+ * based on the disclosed information by MEI.
+ *
+ * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.4 first post version
+ * add function to retrive SIFR
+ *
+ * Jul.24, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.3 get proper status of hotkey
+ *
+ * Jul.22, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.2 add HotKey handler
+ *
+ * Jul.17, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.1 start from toshiba_acpi driver written by John Belmonte
+ *
+ */
+
+#define ACPI_PCC_VERSION "0.9+hy"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+/*************************************************************************
+ * "seq" file template definition.
+ */
+/* "seq" initializer */
+#define SEQ_OPEN_FS(_open_func_name_, _show_func_name_) \
+static int _open_func_name_(struct inode *inode, struct file *file) \
+{ \
+ return single_open(file, _show_func_name_, PDE(inode)->data); \
+}
+
+/*-------------------------------------------------------------------------
+ * "seq" fops template for read-only files.
+ */
+#define SEQ_FILEOPS_R(_open_func_name_) \
+{ \
+ .open = _open_func_name_, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+}
+
+/*------------------------------------------------------------------------
+ * "seq" fops template for read-write files.
+ */
+#define SEQ_FILEOPS_RW(_open_func_name_, _write_func_name_) \
+{ \
+ .open = _open_func_name_ , \
+ .read = seq_read, \
+ .write = _write_func_name_, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+}
+
+/*
+ * "seq" file template definition ended.
+ ***************************************************************************
+ */
+#ifndef ACPI_HOTKEY_COMPONENT
+#define ACPI_HOTKEY_COMPONENT 0x10000000
+#endif
+
+#define _COMPONENT ACPI_HOTKEY_COMPONENT
+ACPI_MODULE_NAME("pcc_acpi");
+
+MODULE_AUTHOR("Hiroshi Miura, Hiroshi Yokota");
+MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops");
+MODULE_LICENSE("GPL");
+
+#define LOGPREFIX "pcc_acpi: "
+
+/****************************************************
+ * Define ACPI PATHs
+ ****************************************************/
+/* Lets note hotkeys */
+#define METHOD_HKEY_QUERY "HINF"
+#define METHOD_HKEY_SQTY "SQTY"
+#define METHOD_HKEY_SINF "SINF"
+#define METHOD_HKEY_SSET "SSET"
+#define HKEY_NOTIFY 0x80
+
+/* for brightness control */
+#define LCD_MAX_BRIGHTNESS 255
+/* This may be magical -- beware */
+#define LCD_BRIGHTNESS_INCREMENT 17
+/* Registers of SINF */
+#define SINF_LCD_BRIGHTNESS 4
+
+/*******************************************************************
+ *
+ * definitions for /proc/ interface
+ *
+ *******************************************************************/
+#define ACPI_PCC_DRIVER_NAME "pcc_acpi"
+#define ACPI_PCC_DEVICE_NAME "PCCExtra"
+#define ACPI_PCC_CLASS "pcc"
+#define PROC_PCC ACPI_PCC_CLASS
+
+#define ACPI_PCC_INPUT_PHYS "panasonic/hkey0"
+
+/* This is transitional definition */
+#ifndef KEY_BATT
+# define KEY_BATT 227
+#endif
+
+#define PROC_STR_MAX_LEN 8
+
+#define BUS_PCC_HOTKEY BUS_I8042 /*0x1a*/ /* FIXME: BUS_I8042? */
+
+/* Fn+F4/F5 confricts with Shift+F1/F2 */
+/* This hack avoids key number confrict */
+#define PCC_KEYINPUT_MODE (0)
+
+/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
+ ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00
+*/
+enum SINF_BITS { SINF_NUM_BATTERIES = 0,
+ SINF_LCD_TYPE,
+ SINF_AC_MAX_BRIGHT,
+ SINF_AC_MIN_BRIGHT,
+ SINF_AC_CUR_BRIGHT,
+ /* 4 = R1 only handle SINF_AC_CUR_BRIGHT
+ * as SINF_CUR_BRIGHT and don't know AC state */
+ SINF_DC_MAX_BRIGHT,
+ SINF_DC_MIN_BRIGHT,
+ SINF_DC_CUR_BRIGHT,
+ SINF_MUTE,
+ SINF_RESERVED,
+ SINF_ENV_STATE, /* 10 */
+ SINF_STICKY_KEY = 0x80,
+};
+
+static struct acpi_device_id pcc_device_ids[] = {
+ {"MAT0012", 0},
+ {"MAT0013", 0},
+ {"MAT0018", 0},
+ {"MAT0019", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, pcc_device_ids);
+
+
+static int __devinit acpi_pcc_hotkey_add(struct acpi_device *device);
+static int __devexit acpi_pcc_hotkey_remove(struct acpi_device *device,
+ int type);
+static int acpi_pcc_hotkey_resume(struct acpi_device *device);
+
+
+static struct acpi_driver acpi_pcc_driver = {
+ .name = ACPI_PCC_DRIVER_NAME,
+ .class = ACPI_PCC_CLASS,
+ .ids = pcc_device_ids,
+ .ops = {
+ .add = acpi_pcc_hotkey_add,
+ .remove = __devexit_p(acpi_pcc_hotkey_remove),
+#ifdef CONFIG_PM
+ /*.suspend = acpi_pcc_hotkey_suspend,*/
+ .resume = acpi_pcc_hotkey_resume,
+#endif
+ },
+};
+
+struct acpi_hotkey {
+ acpi_handle handle;
+ struct acpi_device *device;
+ struct proc_dir_entry *proc_dir_entry;
+ unsigned long num_sifr;
+ unsigned long status;
+ struct input_dev *input_dev;
+ int sticky_mode;
+};
+
+struct pcc_keyinput {
+ struct acpi_hotkey *hotkey;
+ int key_mode;
+};
+
+/* *************************************************************************
+ Hotkey driver core
+ ************************************************************************* */
+/* -------------------------------------------------------------------------
+ method access functions
+ ------------------------------------------------------------------------- */
+static int acpi_pcc_write_sset(struct acpi_hotkey *hotkey, int func, int val)
+{
+ union acpi_object in_objs[] = {
+ { .integer.type = ACPI_TYPE_INTEGER,
+ .integer.value = func, },
+ { .integer.type = ACPI_TYPE_INTEGER,
+ .integer.value = val, },
+ };
+ struct acpi_object_list params = {
+ .count = ARRAY_SIZE(in_objs),
+ .pointer = in_objs,
+ };
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_write_sset");
+
+ status = acpi_evaluate_object(hotkey->handle, METHOD_HKEY_SSET,
+ &params, NULL);
+
+ return_VALUE(status == AE_OK ? AE_OK : AE_ERROR);
+}
+
+static inline int acpi_pcc_get_sqty(struct acpi_device *device)
+{
+ unsigned 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)) {
+ return_VALUE(s);
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "evaluation error HKEY.SQTY\n"));
+ return_VALUE(-EINVAL);
+ }
+}
+
+static int acpi_pcc_retrieve_biosdata(struct acpi_hotkey *hotkey, u32 *sinf)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *hkey = NULL;
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata");
+
+ status = acpi_evaluate_object(hotkey->handle, METHOD_HKEY_SINF, 0,
+ &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "evaluation error HKEY.SINF\n"));
+ status = AE_ERROR;
+ return_VALUE(status);
+ }
+
+ hkey = buffer.pointer;
+ if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
+ goto free_buffer;
+ }
+
+ if (hotkey->num_sifr < hkey->package.count) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "SQTY reports bad SINF length\n"));
+ status = AE_ERROR;
+ goto free_buffer;
+ }
+
+ for (i = 0; i < hkey->package.count; i++) {
+ union acpi_object *element = &(hkey->package.elements[i]);
+ if (likely(element->type == ACPI_TYPE_INTEGER)) {
+ sinf[i] = element->integer.value;
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Invalid HKEY.SINF data\n"));
+ status = AE_ERROR;
+ break;
+ }
+ }
+ sinf[hkey->package.count] = -1;
+
+ free_buffer:
+ kfree(buffer.pointer);
+ return_VALUE(status == AE_OK ? AE_OK : AE_ERROR);
+}
+
+static int acpi_pcc_read_sinf_field(struct seq_file *seq, int field)
+{
+ struct acpi_hotkey *hotkey = (struct acpi_hotkey *) seq->private;
+ u32 sinf[hotkey->num_sifr + 1];
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_read_sinf_field");
+
+ if (ACPI_SUCCESS(acpi_pcc_retrieve_biosdata(hotkey, sinf)))
+ seq_printf(seq, "%u\n", sinf[field]);
+ else
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't retrieve BIOS data\n"));
+
+ return_VALUE(AE_OK);
+}
+
+/* -------------------------------------------------------------------------
+ user interface functions
+ ------------------------------------------------------------------------- */
+/* read methods */
+/* Sinf read methods */
+#define PCC_SINF_READ_F(_name_, FUNC) \
+static int _name_(struct seq_file *seq, void *offset) \
+{ \
+ return_VALUE(ACPI_SUCCESS(acpi_pcc_read_sinf_field(seq, \
+ (FUNC))) \
+ ? 0 : -EINVAL); \
+}
+
+PCC_SINF_READ_F(acpi_pcc_numbatteries_show, SINF_NUM_BATTERIES);
+PCC_SINF_READ_F(acpi_pcc_lcdtype_show, SINF_LCD_TYPE);
+PCC_SINF_READ_F(acpi_pcc_ac_brightness_max_show, SINF_AC_MAX_BRIGHT);
+PCC_SINF_READ_F(acpi_pcc_ac_brightness_min_show, SINF_AC_MIN_BRIGHT);
+PCC_SINF_READ_F(acpi_pcc_ac_brightness_show, SINF_AC_CUR_BRIGHT);
+PCC_SINF_READ_F(acpi_pcc_dc_brightness_max_show, SINF_DC_MAX_BRIGHT);
+PCC_SINF_READ_F(acpi_pcc_dc_brightness_min_show, SINF_DC_MIN_BRIGHT);
+PCC_SINF_READ_F(acpi_pcc_dc_brightness_show, SINF_DC_CUR_BRIGHT);
+PCC_SINF_READ_F(acpi_pcc_brightness_show, SINF_AC_CUR_BRIGHT);
+PCC_SINF_READ_F(acpi_pcc_mute_show, SINF_MUTE);
+
+static int acpi_pcc_sticky_key_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_hotkey *hotkey = seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_sticky_key_show");
+
+ if (!hotkey || !hotkey->device)
+ return_VALUE(-EINVAL);
+
+ seq_printf(seq, "%d\n", hotkey->sticky_mode);
+
+ return_VALUE(0);
+}
+
+static int acpi_pcc_keyinput_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_hotkey *hotkey = seq->private;
+ struct input_dev *hotk_input_dev = hotkey->input_dev;
+ struct pcc_keyinput *keyinput = input_get_drvdata(hotk_input_dev);
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_keyinput_show");
+
+ seq_printf(seq, "%d\n", keyinput->key_mode);
+
+ return_VALUE(0);
+}
+
+static int acpi_pcc_version_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_hotkey *hotkey = seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_version_show");
+
+ if (!hotkey || !hotkey->device)
+ return_VALUE(-EINVAL);
+
+ seq_printf(seq, "%s version %s\n", ACPI_PCC_DRIVER_NAME,
+ ACPI_PCC_VERSION);
+ seq_printf(seq, "%li functions\n", hotkey->num_sifr);
+
+ return_VALUE(0);
+}
+
+/* write methods */
+static ssize_t acpi_pcc_write_single_flag(struct file *file,
+ const char __user *buffer,
+ size_t count,
+ int sinf_func)
+{
+ struct seq_file *seq = file->private_data;
+ struct acpi_hotkey *hotkey = seq->private;
+ char write_string[PROC_STR_MAX_LEN];
+ u32 val;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_write_single_flag");
+
+ if (!hotkey || (count > sizeof(write_string) - 1))
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(write_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ write_string[count] = '\0';
+
+ if ((sscanf(write_string, "%3i", &val) == 1) &&
+ (val == 0 || val == 1))
+ acpi_pcc_write_sset(hotkey, sinf_func, val);
+
+ return_VALUE(count);
+}
+
+static unsigned long acpi_pcc_write_brightness(struct file *file,
+ const char __user *buffer,
+ size_t count,
+ int min_index, int max_index,
+ int cur_index)
+{
+ struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct acpi_hotkey *hotkey = (struct acpi_hotkey *)seq->private;
+ char write_string[PROC_STR_MAX_LEN];
+ u32 bright;
+ u32 sinf[hotkey->num_sifr + 1];
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_write_brightness");
+
+ if (!hotkey || (count > sizeof(write_string) - 1))
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(write_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ write_string[count] = '\0';
+
+ if (ACPI_FAILURE(acpi_pcc_retrieve_biosdata(hotkey, sinf))) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't retrieve BIOS data\n"));
+ goto end;
+ }
+
+ if ((sscanf(write_string, "%4i", &bright) == 1) &&
+ (bright >= sinf[min_index]) &&
+ (bright <= sinf[max_index]))
+ acpi_pcc_write_sset(hotkey, cur_index, bright);
+
+end:
+ return_VALUE(count);
+}
+
+static ssize_t acpi_pcc_write_ac_brightness(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return_VALUE(acpi_pcc_write_brightness(file, buffer, count,
+ SINF_AC_MIN_BRIGHT,
+ SINF_AC_MAX_BRIGHT,
+ SINF_AC_CUR_BRIGHT));
+}
+
+static ssize_t acpi_pcc_write_dc_brightness(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return_VALUE(acpi_pcc_write_brightness(file, buffer, count,
+ SINF_DC_MIN_BRIGHT,
+ SINF_DC_MAX_BRIGHT,
+ SINF_DC_CUR_BRIGHT));
+}
+
+static ssize_t acpi_pcc_write_no_brightness(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return acpi_pcc_write_brightness(file, buffer, count,
+ SINF_AC_MIN_BRIGHT,
+ SINF_AC_MAX_BRIGHT,
+ SINF_AC_CUR_BRIGHT);
+}
+
+static ssize_t acpi_pcc_write_mute(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return_VALUE(acpi_pcc_write_single_flag(file, buffer, count,
+ SINF_MUTE));
+}
+
+static ssize_t acpi_pcc_write_sticky_key(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct acpi_hotkey *hotkey = (struct acpi_hotkey *)seq->private;
+ char write_string[PROC_STR_MAX_LEN];
+ int mode;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_write_sticky_key");
+
+ if (!hotkey || (count > sizeof(write_string) - 1))
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(write_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ write_string[count] = '\0';
+
+ if ((sscanf(write_string, "%3i", &mode) == 1) &&
+ (mode == 0 || mode == 1)) {
+ acpi_pcc_write_sset(hotkey, SINF_STICKY_KEY, mode);
+ hotkey->sticky_mode = mode;
+ }
+
+ return_VALUE(count);
+}
+
+static ssize_t acpi_pcc_write_keyinput(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct acpi_hotkey *hotkey = (struct acpi_hotkey *)seq->private;
+ struct pcc_keyinput *keyinput;
+ char write_string[PROC_STR_MAX_LEN];
+ int key_mode;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_write_keyinput");
+
+ if (!hotkey || (count > (sizeof(write_string) - 1)))
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(write_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ write_string[count] = '\0';
+
+ if ((sscanf(write_string, "%4i", &key_mode) == 1) &&
+ (key_mode == 0 || key_mode == 1)) {
+ keyinput = input_get_drvdata(hotkey->input_dev);
+ keyinput->key_mode = key_mode;
+ }
+
+ return_VALUE(count);
+}
+
+/* -------------------------------------------------------------------------
+ hotkey driver
+ ------------------------------------------------------------------------- */
+static void acpi_pcc_generete_keyinput(struct acpi_hotkey *hotkey)
+{
+ struct input_dev *hotk_input_dev = hotkey->input_dev;
+ struct pcc_keyinput *keyinput = input_get_drvdata(hotk_input_dev);
+ int hinf = hotkey->status;
+ int key_code, hkey_num;
+ const int key_map[] = {
+ /* 0 */ -1,
+ /* 1 */ KEY_BRIGHTNESSDOWN,
+ /* 2 */ KEY_BRIGHTNESSUP,
+ /* 3 */ -1, /* vga/lcd switch event is not occur on
+ hotkey driver. */
+ /* 4 */ KEY_MUTE,
+ /* 5 */ KEY_VOLUMEDOWN,
+ /* 6 */ KEY_VOLUMEUP,
+ /* 7 */ KEY_SLEEP,
+ /* 8 */ -1, /* Change CPU boost: do nothing */
+ /* 9 */ KEY_BATT,
+ /* 10 */ KEY_SUSPEND,
+ };
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_generete_keyinput");
+
+ if (keyinput->key_mode == 0)
+ return_VOID;
+
+ hkey_num = hinf & 0xf;
+
+ if ((0 > hkey_num) ||
+ (hkey_num > ARRAY_SIZE(key_map))) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "hotkey number out of range: %d\n",
+ hkey_num));
+ return_VOID;
+ }
+
+ key_code = key_map[hkey_num];
+
+ if (key_code != -1) {
+ int pushed = (hinf & 0x80) ? TRUE : FALSE;
+
+ input_report_key(hotk_input_dev, key_code, pushed);
+ input_sync(hotk_input_dev);
+ }
+}
+
+static int acpi_pcc_hotkey_get_key(struct acpi_hotkey *hotkey)
+{
+ unsigned long result;
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_get_key");
+
+ status = acpi_evaluate_integer(hotkey->handle, METHOD_HKEY_QUERY,
+ NULL, &result);
+ if (likely(ACPI_SUCCESS(status)))
+ hotkey->status = result;
+ else
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "error getting hotkey status\n"));
+
+ return_VALUE(status == AE_OK);
+}
+
+void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct acpi_hotkey *hotkey = (struct acpi_hotkey *) data;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify");
+
+ switch (event) {
+ case HKEY_NOTIFY:
+ if (acpi_pcc_hotkey_get_key(hotkey)) {
+ /* generate event like '"pcc HKEY 00000080 00000084"'
+ * when Fn+F4 pressed */
+ acpi_bus_generate_proc_event(hotkey->device, event,
+ hotkey->status);
+ }
+ acpi_pcc_generete_keyinput(hotkey);
+ break;
+ default:
+ /* nothing to do */
+ break;
+ }
+ return_VOID;
+}
+
+/* *************************************************************************
+ FS Interface (/proc)
+ ************************************************************************* */
+/* oepn proc file fs*/
+SEQ_OPEN_FS(acpi_pcc_dc_brightness_open_fs, acpi_pcc_dc_brightness_show);
+SEQ_OPEN_FS(acpi_pcc_numbatteries_open_fs, acpi_pcc_numbatteries_show);
+SEQ_OPEN_FS(acpi_pcc_lcdtype_open_fs, acpi_pcc_lcdtype_show);
+SEQ_OPEN_FS(acpi_pcc_ac_brightness_max_open_fs,
+ acpi_pcc_ac_brightness_max_show);
+SEQ_OPEN_FS(acpi_pcc_ac_brightness_min_open_fs,
+ acpi_pcc_ac_brightness_min_show);
+SEQ_OPEN_FS(acpi_pcc_ac_brightness_open_fs, acpi_pcc_ac_brightness_show);
+SEQ_OPEN_FS(acpi_pcc_dc_brightness_max_open_fs,
+ acpi_pcc_dc_brightness_max_show);
+SEQ_OPEN_FS(acpi_pcc_dc_brightness_min_open_fs,
+ acpi_pcc_dc_brightness_min_show);
+SEQ_OPEN_FS(acpi_pcc_brightness_open_fs, acpi_pcc_brightness_show);
+SEQ_OPEN_FS(acpi_pcc_mute_open_fs, acpi_pcc_mute_show);
+SEQ_OPEN_FS(acpi_pcc_version_open_fs, acpi_pcc_version_show);
+SEQ_OPEN_FS(acpi_pcc_keyinput_open_fs, acpi_pcc_keyinput_show);
+SEQ_OPEN_FS(acpi_pcc_sticky_key_open_fs, acpi_pcc_sticky_key_show);
+
+static struct file_operations acpi_pcc_numbatteries_fops =
+ SEQ_FILEOPS_R(acpi_pcc_numbatteries_open_fs);
+static struct file_operations acpi_pcc_lcdtype_fops =
+ SEQ_FILEOPS_R(acpi_pcc_lcdtype_open_fs);
+static struct file_operations acpi_pcc_mute_fops =
+ SEQ_FILEOPS_RW(acpi_pcc_mute_open_fs, acpi_pcc_write_mute);
+static struct file_operations acpi_pcc_ac_brightness_fops =
+ SEQ_FILEOPS_RW(acpi_pcc_ac_brightness_open_fs,
+ acpi_pcc_write_ac_brightness);
+static struct file_operations acpi_pcc_ac_brightness_max_fops =
+ SEQ_FILEOPS_R(acpi_pcc_ac_brightness_max_open_fs);
+static struct file_operations acpi_pcc_ac_brightness_min_fops =
+ SEQ_FILEOPS_R(acpi_pcc_ac_brightness_min_open_fs);
+static struct file_operations acpi_pcc_dc_brightness_fops =
+ SEQ_FILEOPS_RW(acpi_pcc_dc_brightness_open_fs,
+ acpi_pcc_write_dc_brightness);
+static struct file_operations acpi_pcc_dc_brightness_max_fops =
+ SEQ_FILEOPS_R(acpi_pcc_dc_brightness_max_open_fs);
+static struct file_operations acpi_pcc_dc_brightness_min_fops =
+ SEQ_FILEOPS_R(acpi_pcc_dc_brightness_min_open_fs);
+static struct file_operations acpi_pcc_brightness_fops =
+ SEQ_FILEOPS_RW(acpi_pcc_brightness_open_fs,
+ acpi_pcc_write_no_brightness);
+static struct file_operations acpi_pcc_sticky_key_fops =
+ SEQ_FILEOPS_RW(acpi_pcc_sticky_key_open_fs, acpi_pcc_write_sticky_key);
+static struct file_operations acpi_pcc_keyinput_fops =
+ SEQ_FILEOPS_RW(acpi_pcc_keyinput_open_fs, acpi_pcc_write_keyinput);
+static struct file_operations acpi_pcc_version_fops =
+ SEQ_FILEOPS_R(acpi_pcc_version_open_fs);
+
+struct proc_item {
+ const char *name;
+ struct file_operations *fops;
+ mode_t flag;
+};
+
+/* Note: These functions map *exactly* to the SINF/SSET functions */
+struct proc_item acpi_pcc_proc_items_sifr[] = {
+ { "num_batteries", &acpi_pcc_numbatteries_fops, S_IRUGO },
+ { "lcd_type", &acpi_pcc_lcdtype_fops, S_IRUGO },
+ { "ac_brightness_max", &acpi_pcc_ac_brightness_max_fops, S_IRUGO },
+ { "ac_brightness_min", &acpi_pcc_ac_brightness_min_fops, S_IRUGO },
+ { "ac_brightness", &acpi_pcc_ac_brightness_fops,
+ S_IFREG | S_IRUGO | S_IWUSR },
+ { "dc_brightness_max", &acpi_pcc_dc_brightness_max_fops, S_IRUGO },
+ { "dc_brightness_min", &acpi_pcc_dc_brightness_min_fops, S_IRUGO },
+ { "dc_brightness", &acpi_pcc_dc_brightness_fops,
+ S_IFREG | S_IRUGO | S_IWUSR },
+ { "brightness", &acpi_pcc_brightness_fops, S_IFREG | S_IRUGO | S_IWUSR},
+ { "mute", &acpi_pcc_mute_fops, S_IFREG | S_IRUGO | S_IWUSR },
+ { NULL, NULL, 0 },
+};
+
+struct proc_item acpi_pcc_proc_items[] = {
+ { "sticky_key", &acpi_pcc_sticky_key_fops, S_IFREG | S_IRUGO | S_IWUSR},
+ { "keyinput", &acpi_pcc_keyinput_fops, S_IFREG | S_IRUGO | S_IWUSR },
+ { "version", &acpi_pcc_version_fops, S_IRUGO },
+ { NULL, NULL, 0 },
+};
+
+static int __devinit acpi_pcc_add_device(struct acpi_device *device,
+ struct proc_item *proc_items,
+ int num)
+{
+ struct acpi_hotkey *hotkey = acpi_driver_data(device);
+ struct proc_dir_entry *proc;
+ struct proc_item *item;
+ int i;
+
+ for (item = proc_items, i = 0; item->name && i < num; ++item, ++i) {
+ proc = create_proc_entry(item->name, item->flag,
+ hotkey->proc_dir_entry);
+ if (likely(proc)) {
+ proc->proc_fops = item->fops;
+ proc->data = hotkey;
+ proc->owner = THIS_MODULE;
+ } else {
+ while (i-- > 0) {
+ item--;
+ remove_proc_entry(item->name,
+ hotkey->proc_dir_entry);
+ }
+ return_VALUE(-ENODEV);
+ }
+ }
+ return_VALUE(0);
+}
+
+static int __devinit acpi_pcc_proc_init(struct acpi_device *device)
+{
+ struct proc_dir_entry *acpi_pcc_dir;
+ struct acpi_hotkey *hotkey = acpi_driver_data(device);
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_proc_init");
+
+ acpi_pcc_dir = proc_mkdir(PROC_PCC, acpi_root_dir);
+
+ if (unlikely(!acpi_pcc_dir)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't create dir in /proc\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ acpi_pcc_dir->owner = THIS_MODULE;
+ hotkey->proc_dir_entry = acpi_pcc_dir;
+
+ status = acpi_pcc_add_device(device, acpi_pcc_proc_items_sifr,
+ hotkey->num_sifr);
+ status |= acpi_pcc_add_device(device, acpi_pcc_proc_items,
+ ARRAY_SIZE(acpi_pcc_proc_items));
+ if (unlikely(status)) {
+ remove_proc_entry(PROC_PCC, acpi_root_dir);
+ hotkey->proc_dir_entry = NULL;
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(status);
+}
+
+static void __devexit acpi_pcc_remove_device(struct acpi_device *device,
+ struct proc_item *proc_items,
+ int num)
+{
+ struct acpi_hotkey *hotkey = acpi_driver_data(device);
+ struct proc_item *item;
+ int i;
+
+ for (item = proc_items, i = 0;
+ item->name != NULL && i < num;
+ ++item, ++i) {
+ remove_proc_entry(item->name, hotkey->proc_dir_entry);
+ }
+
+ return_VOID;
+}
+
+/* *************************************************************************
+ Power Management
+ ************************************************************************* */
+#ifdef CONFIG_PM
+static int acpi_pcc_hotkey_resume(struct acpi_device *device)
+{
+ struct acpi_hotkey *hotkey = acpi_driver_data(device);
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume");
+
+ if (device == NULL || hotkey == NULL)
+ return_VALUE(-EINVAL);
+
+ if (hotkey->num_sifr != 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Sticky mode restore: %d\n",
+ hotkey->sticky_mode));
+
+ status = acpi_pcc_write_sset(hotkey, SINF_STICKY_KEY,
+ hotkey->sticky_mode);
+ }
+ if (status != AE_OK)
+ return_VALUE(-EINVAL);
+
+ return_VALUE(0);
+}
+#endif
+
+/* *************************************************************************
+ Module init/remove
+ ************************************************************************* */
+/* -------------------------------------------------------------------------
+ input
+ ------------------------------------------------------------------------- */
+static int __devinit acpi_pcc_init_input(struct acpi_hotkey *hotkey)
+{
+ struct input_dev *hotk_input_dev;
+ struct pcc_keyinput *pcc_keyinput;
+ int error;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_init_input");
+
+ hotk_input_dev = input_allocate_device();
+ if (hotk_input_dev == NULL) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't allocate input device for hotkey"));
+ goto err_input;
+ }
+
+ pcc_keyinput = kcalloc(1, sizeof(struct pcc_keyinput), GFP_KERNEL);
+
+ if (pcc_keyinput == NULL) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't allocate mem for private data"));
+ goto err_pcc;
+ }
+
+ hotk_input_dev->evbit[0] = BIT(EV_KEY);
+
+ set_bit(KEY_BRIGHTNESSDOWN, hotk_input_dev->keybit);
+ set_bit(KEY_BRIGHTNESSUP, hotk_input_dev->keybit);
+ set_bit(KEY_MUTE, hotk_input_dev->keybit);
+ set_bit(KEY_VOLUMEDOWN, hotk_input_dev->keybit);
+ set_bit(KEY_VOLUMEUP, hotk_input_dev->keybit);
+ set_bit(KEY_SLEEP, hotk_input_dev->keybit);
+ set_bit(KEY_BATT, hotk_input_dev->keybit);
+ set_bit(KEY_SUSPEND, hotk_input_dev->keybit);
+
+ hotk_input_dev->name = ACPI_PCC_DRIVER_NAME;
+ hotk_input_dev->phys = ACPI_PCC_INPUT_PHYS;
+ hotk_input_dev->id.bustype = BUS_PCC_HOTKEY;
+ hotk_input_dev->id.vendor = 0x0001;
+ hotk_input_dev->id.product = 0x0001;
+ hotk_input_dev->id.version = 0x0100;
+
+ pcc_keyinput->key_mode = PCC_KEYINPUT_MODE;
+ pcc_keyinput->hotkey = hotkey;
+
+ input_set_drvdata(hotk_input_dev, pcc_keyinput);
+
+ hotkey->input_dev = hotk_input_dev;
+
+ error = input_register_device(hotk_input_dev);
+
+ if (error)
+ goto err_pcc;
+
+ return_VALUE(0);
+
+ err_pcc:
+ input_unregister_device(hotk_input_dev);
+ err_input:
+ return_VALUE(-ENOMEM);
+}
+
+static void __devexit acpi_pcc_remove_input(struct acpi_hotkey *hotkey)
+{
+ struct input_dev *hotk_input_dev;
+ struct pcc_keyinput *pcc_keyinput;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_remove_input");
+
+ if (hotkey == NULL) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Can't free memory"));
+ return_VOID;
+ }
+
+ hotk_input_dev = hotkey->input_dev;
+ pcc_keyinput = input_get_drvdata(hotk_input_dev);
+
+ input_unregister_device(hotk_input_dev);
+
+ kfree(pcc_keyinput);
+}
+
+/* -------------------------------------------------------------------------
+ ACPI
+ ------------------------------------------------------------------------- */
+static int __devinit acpi_pcc_hotkey_add(struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ struct acpi_hotkey *hotkey = NULL;
+ int sifr_status, num_sifr, result;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add");
+
+ if (device == NULL)
+ return_VALUE(-EINVAL);
+
+ sifr_status = acpi_pcc_get_sqty(device);
+
+ if (sifr_status > 255) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large"));
+ return_VALUE(-ENODEV);
+ }
+
+ if (sifr_status < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "not support SQTY"));
+ num_sifr = 0;
+ } else {
+ num_sifr = sifr_status;
+ }
+
+ hotkey = kcalloc(1, sizeof(struct acpi_hotkey), GFP_KERNEL);
+ if (hotkey == NULL) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't allocate mem for hotkey"));
+ return_VALUE(-ENOMEM);
+ }
+
+ hotkey->device = device;
+ hotkey->handle = device->handle;
+ hotkey->num_sifr = num_sifr;
+ device->driver_data = hotkey;
+ strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PCC_CLASS);
+
+ status = acpi_install_notify_handler(hotkey->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_pcc_hotkey_notify,
+ hotkey);
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ kfree(hotkey);
+ return_VALUE(-ENODEV);
+ }
+
+ result = acpi_pcc_init_input(hotkey);
+ if (result != 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing keyinput handler\n"));
+ kfree(hotkey);
+ return_VALUE(result);
+ }
+
+ return_VALUE(acpi_pcc_proc_init(device));
+}
+
+static int __devexit acpi_pcc_hotkey_remove(struct acpi_device *device,
+ int type)
+{
+ acpi_status status = AE_OK;
+ struct acpi_hotkey *hotkey = acpi_driver_data(device);
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove");
+
+ if (!device || !hotkey)
+ return_VALUE(-EINVAL);
+
+ if (hotkey->proc_dir_entry) {
+ acpi_pcc_remove_device(device, acpi_pcc_proc_items_sifr,
+ hotkey->num_sifr);
+ acpi_pcc_remove_device(device, acpi_pcc_proc_items,
+ ARRAY_SIZE(acpi_pcc_proc_items));
+ remove_proc_entry(PROC_PCC, acpi_root_dir);
+ }
+
+ status = acpi_remove_notify_handler(hotkey->handle,
+ ACPI_DEVICE_NOTIFY, acpi_pcc_hotkey_notify);
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error removing notify handler\n"));
+ }
+
+ acpi_pcc_remove_input(hotkey);
+ kfree(hotkey);
+ return_VALUE(status == AE_OK);
+}
+
+/* *********************************************************************
+ Module entry point
+ ********************************************************************* */
+static int __init acpi_pcc_init(void)
+{
+ int result;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_init");
+
+ printk(KERN_INFO LOGPREFIX "loading...\n");
+
+ if (acpi_disabled) {
+ printk(KERN_INFO LOGPREFIX "ACPI disabled.\n");
+ return_VALUE(-ENODEV);
+ }
+
+ result = acpi_bus_register_driver(&acpi_pcc_driver);
+ if (result < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error registering hotkey driver\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(result);
+}
+
+static void __exit acpi_pcc_exit(void)
+{
+ ACPI_FUNCTION_TRACE("acpi_pcc_exit");
+
+ printk(KERN_INFO LOGPREFIX "unloading...\n");
+
+ acpi_bus_unregister_driver(&acpi_pcc_driver);
+
+ return_VOID;
+}
+
+module_init(acpi_pcc_init);
+module_exit(acpi_pcc_exit);
diff --git a/drivers/staging/poch/Kconfig b/drivers/staging/poch/Kconfig
new file mode 100644
index 00000000000..b3b33b984a5
--- /dev/null
+++ b/drivers/staging/poch/Kconfig
@@ -0,0 +1,6 @@
+config POCH
+ tristate "Redrapids Pocket Change CardBus support"
+ depends on PCI && UIO
+ default N
+ ---help---
+ Enable support for Redrapids Pocket Change CardBus devices.
diff --git a/drivers/staging/poch/Makefile b/drivers/staging/poch/Makefile
new file mode 100644
index 00000000000..d2b96805cb9
--- /dev/null
+++ b/drivers/staging/poch/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_POCH) += poch.o
diff --git a/drivers/staging/poch/README b/drivers/staging/poch/README
new file mode 100644
index 00000000000..f65e979743b
--- /dev/null
+++ b/drivers/staging/poch/README
@@ -0,0 +1,7 @@
+TODO:
+ - fix transmit overflows
+ - audit userspace interfaces
+ - get reserved major/minor if needed
+
+Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
+Vijay Kumar <vijaykumar@bravegnu.org> and Jaya Kumar <jayakumar.lkml@gmail.com>
diff --git a/drivers/staging/poch/poch.c b/drivers/staging/poch/poch.c
new file mode 100644
index 00000000000..0e113f9a158
--- /dev/null
+++ b/drivers/staging/poch/poch.c
@@ -0,0 +1,1425 @@
+/*
+ * User-space DMA and UIO based Redrapids Pocket Change CardBus driver
+ *
+ * Copyright 2008 Vijay Kumar <vijaykumar@bravegnu.org>
+ *
+ * Licensed under GPL version 2 only.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+#include <linux/spinlock.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/poll.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/io.h>
+
+#include "poch.h"
+
+#include <asm/cacheflush.h>
+
+#ifndef PCI_VENDOR_ID_RRAPIDS
+#define PCI_VENDOR_ID_RRAPIDS 0x17D2
+#endif
+
+#ifndef PCI_DEVICE_ID_RRAPIDS_POCKET_CHANGE
+#define PCI_DEVICE_ID_RRAPIDS_POCKET_CHANGE 0x0351
+#endif
+
+#define POCH_NCHANNELS 2
+
+#define MAX_POCH_CARDS 8
+#define MAX_POCH_DEVICES (MAX_POCH_CARDS * POCH_NCHANNELS)
+
+#define DRV_NAME "poch"
+#define PFX DRV_NAME ": "
+
+/*
+ * BAR0 Bridge Register Definitions
+ */
+
+#define BRIDGE_REV_REG 0x0
+#define BRIDGE_INT_MASK_REG 0x4
+#define BRIDGE_INT_STAT_REG 0x8
+
+#define BRIDGE_INT_ACTIVE (0x1 << 31)
+#define BRIDGE_INT_FPGA (0x1 << 2)
+#define BRIDGE_INT_TEMP_FAIL (0x1 << 1)
+#define BRIDGE_INT_TEMP_WARN (0x1 << 0)
+
+#define BRIDGE_FPGA_RESET_REG 0xC
+
+#define BRIDGE_CARD_POWER_REG 0x10
+#define BRIDGE_CARD_POWER_EN (0x1 << 0)
+#define BRIDGE_CARD_POWER_PROG_DONE (0x1 << 31)
+
+#define BRIDGE_JTAG_REG 0x14
+#define BRIDGE_DMA_GO_REG 0x18
+#define BRIDGE_STAT_0_REG 0x1C
+#define BRIDGE_STAT_1_REG 0x20
+#define BRIDGE_STAT_2_REG 0x24
+#define BRIDGE_STAT_3_REG 0x28
+#define BRIDGE_TEMP_STAT_REG 0x2C
+#define BRIDGE_TEMP_THRESH_REG 0x30
+#define BRIDGE_EEPROM_REVSEL_REG 0x34
+#define BRIDGE_CIS_STRUCT_REG 0x100
+#define BRIDGE_BOARDREV_REG 0x124
+
+/*
+ * BAR1 FPGA Register Definitions
+ */
+
+#define FPGA_IFACE_REV_REG 0x0
+#define FPGA_RX_BLOCK_SIZE_REG 0x8
+#define FPGA_TX_BLOCK_SIZE_REG 0xC
+#define FPGA_RX_BLOCK_COUNT_REG 0x10
+#define FPGA_TX_BLOCK_COUNT_REG 0x14
+#define FPGA_RX_CURR_DMA_BLOCK_REG 0x18
+#define FPGA_TX_CURR_DMA_BLOCK_REG 0x1C
+#define FPGA_RX_GROUP_COUNT_REG 0x20
+#define FPGA_TX_GROUP_COUNT_REG 0x24
+#define FPGA_RX_CURR_GROUP_REG 0x28
+#define FPGA_TX_CURR_GROUP_REG 0x2C
+#define FPGA_RX_CURR_PCI_REG 0x38
+#define FPGA_TX_CURR_PCI_REG 0x3C
+#define FPGA_RX_GROUP0_START_REG 0x40
+#define FPGA_TX_GROUP0_START_REG 0xC0
+#define FPGA_DMA_DESC_1_REG 0x140
+#define FPGA_DMA_DESC_2_REG 0x144
+#define FPGA_DMA_DESC_3_REG 0x148
+#define FPGA_DMA_DESC_4_REG 0x14C
+
+#define FPGA_DMA_INT_STAT_REG 0x150
+#define FPGA_DMA_INT_MASK_REG 0x154
+#define FPGA_DMA_INT_RX (1 << 0)
+#define FPGA_DMA_INT_TX (1 << 1)
+
+#define FPGA_RX_GROUPS_PER_INT_REG 0x158
+#define FPGA_TX_GROUPS_PER_INT_REG 0x15C
+#define FPGA_DMA_ADR_PAGE_REG 0x160
+#define FPGA_FPGA_REV_REG 0x200
+
+#define FPGA_ADC_CLOCK_CTL_REG 0x204
+#define FPGA_ADC_CLOCK_CTL_OSC_EN (0x1 << 3)
+#define FPGA_ADC_CLOCK_LOCAL_CLK (0x1 | FPGA_ADC_CLOCK_CTL_OSC_EN)
+#define FPGA_ADC_CLOCK_EXT_SAMP_CLK 0X0
+
+#define FPGA_ADC_DAC_EN_REG 0x208
+#define FPGA_ADC_DAC_EN_DAC_OFF (0x1 << 1)
+#define FPGA_ADC_DAC_EN_ADC_OFF (0x1 << 0)
+
+#define FPGA_INT_STAT_REG 0x20C
+#define FPGA_INT_MASK_REG 0x210
+#define FPGA_INT_PLL_UNLOCKED (0x1 << 9)
+#define FPGA_INT_DMA_CORE (0x1 << 8)
+#define FPGA_INT_TX_FF_EMPTY (0x1 << 7)
+#define FPGA_INT_RX_FF_EMPTY (0x1 << 6)
+#define FPGA_INT_TX_FF_OVRFLW (0x1 << 3)
+#define FPGA_INT_RX_FF_OVRFLW (0x1 << 2)
+#define FPGA_INT_TX_ACQ_DONE (0x1 << 1)
+#define FPGA_INT_RX_ACQ_DONE (0x1)
+
+#define FPGA_RX_ADC_CTL_REG 0x214
+#define FPGA_RX_ADC_CTL_CONT_CAP (0x0)
+#define FPGA_RX_ADC_CTL_SNAP_CAP (0x1)
+
+#define FPGA_RX_ARM_REG 0x21C
+
+#define FPGA_DOM_REG 0x224
+#define FPGA_DOM_DCM_RESET (0x1 << 5)
+#define FPGA_DOM_SOFT_RESET (0x1 << 4)
+#define FPGA_DOM_DUAL_M_SG_DMA (0x0)
+#define FPGA_DOM_TARGET_ACCESS (0x1)
+
+#define FPGA_TX_CTL_REG 0x228
+#define FPGA_TX_CTL_FIFO_FLUSH (0x1 << 9)
+#define FPGA_TX_CTL_OUTPUT_ZERO (0x0 << 2)
+#define FPGA_TX_CTL_OUTPUT_CARDBUS (0x1 << 2)
+#define FPGA_TX_CTL_OUTPUT_ADC (0x2 << 2)
+#define FPGA_TX_CTL_OUTPUT_SNAPSHOT (0x3 << 2)
+#define FPGA_TX_CTL_LOOPBACK (0x1 << 0)
+
+#define FPGA_ENDIAN_MODE_REG 0x22C
+#define FPGA_RX_FIFO_COUNT_REG 0x28C
+#define FPGA_TX_ENABLE_REG 0x298
+#define FPGA_TX_TRIGGER_REG 0x29C
+#define FPGA_TX_DATAMEM_COUNT_REG 0x2A8
+#define FPGA_CAP_FIFO_REG 0x300
+#define FPGA_TX_SNAPSHOT_REG 0x8000
+
+/*
+ * Channel Index Definitions
+ */
+
+enum {
+ CHNO_RX_CHANNEL,
+ CHNO_TX_CHANNEL,
+};
+
+struct poch_dev;
+
+enum channel_dir {
+ CHANNEL_DIR_RX,
+ CHANNEL_DIR_TX,
+};
+
+struct poch_group_info {
+ struct page *pg;
+ dma_addr_t dma_addr;
+ unsigned long user_offset;
+};
+
+struct channel_info {
+ unsigned int chno;
+
+ atomic_t sys_block_size;
+ atomic_t sys_group_size;
+ atomic_t sys_group_count;
+
+ enum channel_dir dir;
+
+ unsigned long block_size;
+ unsigned long group_size;
+ unsigned long group_count;
+
+ /* Contains the DMA address and VM offset of each group. */
+ struct poch_group_info *groups;
+
+ /* Contains the header and circular buffer exported to userspace. */
+ spinlock_t group_offsets_lock;
+ struct poch_cbuf_header *header;
+ struct page *header_pg;
+ unsigned long header_size;
+
+ /* Last group indicated as 'complete' to user space. */
+ unsigned int transfer;
+
+ wait_queue_head_t wq;
+
+ union {
+ unsigned int data_available;
+ unsigned int space_available;
+ };
+
+ void __iomem *bridge_iomem;
+ void __iomem *fpga_iomem;
+ spinlock_t *iomem_lock;
+
+ atomic_t free;
+ atomic_t inited;
+
+ /* Error counters */
+ struct poch_counters counters;
+ spinlock_t counters_lock;
+
+ struct device *dev;
+};
+
+struct poch_dev {
+ struct uio_info uio;
+ struct pci_dev *pci_dev;
+ unsigned int nchannels;
+ struct channel_info channels[POCH_NCHANNELS];
+ struct cdev cdev;
+
+ /* Counts the no. of channels that have been opened. On first
+ * open, the card is powered on. On last channel close, the
+ * card is powered off.
+ */
+ atomic_t usage;
+
+ void __iomem *bridge_iomem;
+ void __iomem *fpga_iomem;
+ spinlock_t iomem_lock;
+
+ struct device *dev;
+};
+
+static dev_t poch_first_dev;
+static struct class *poch_cls;
+static DEFINE_IDR(poch_ids);
+
+static ssize_t store_block_size(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct channel_info *channel = dev_get_drvdata(dev);
+ unsigned long block_size;
+
+ sscanf(buf, "%lu", &block_size);
+ atomic_set(&channel->sys_block_size, block_size);
+
+ return count;
+}
+static DEVICE_ATTR(block_size, S_IWUSR|S_IWGRP, NULL, store_block_size);
+
+static ssize_t store_group_size(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct channel_info *channel = dev_get_drvdata(dev);
+ unsigned long group_size;
+
+ sscanf(buf, "%lu", &group_size);
+ atomic_set(&channel->sys_group_size, group_size);
+
+ return count;
+}
+static DEVICE_ATTR(group_size, S_IWUSR|S_IWGRP, NULL, store_group_size);
+
+static ssize_t store_group_count(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct channel_info *channel = dev_get_drvdata(dev);
+ unsigned long group_count;
+
+ sscanf(buf, "%lu", &group_count);
+ atomic_set(&channel->sys_group_count, group_count);
+
+ return count;
+}
+static DEVICE_ATTR(group_count, S_IWUSR|S_IWGRP, NULL, store_group_count);
+
+static ssize_t show_direction(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct channel_info *channel = dev_get_drvdata(dev);
+ int len;
+
+ len = sprintf(buf, "%s\n", (channel->dir ? "tx" : "rx"));
+ return len;
+}
+static DEVICE_ATTR(dir, S_IRUSR|S_IRGRP, show_direction, NULL);
+
+static ssize_t show_mmap_size(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct channel_info *channel = dev_get_drvdata(dev);
+ int len;
+ unsigned long mmap_size;
+ unsigned long group_pages;
+ unsigned long header_pages;
+ unsigned long total_group_pages;
+
+ /* FIXME: We do not have to add 1, if group_size a multiple of
+ PAGE_SIZE. */
+ group_pages = (channel->group_size / PAGE_SIZE) + 1;
+ header_pages = (channel->header_size / PAGE_SIZE) + 1;
+ total_group_pages = group_pages * channel->group_count;
+
+ mmap_size = (header_pages + total_group_pages) * PAGE_SIZE;
+ len = sprintf(buf, "%lu\n", mmap_size);
+ return len;
+}
+static DEVICE_ATTR(mmap_size, S_IRUSR|S_IRGRP, show_mmap_size, NULL);
+
+static struct device_attribute *poch_class_attrs[] = {
+ &dev_attr_block_size,
+ &dev_attr_group_size,
+ &dev_attr_group_count,
+ &dev_attr_dir,
+ &dev_attr_mmap_size,
+};
+
+static void poch_channel_free_groups(struct channel_info *channel)
+{
+ unsigned long i;
+
+ for (i = 0; i < channel->group_count; i++) {
+ struct poch_group_info *group;
+ unsigned int order;
+
+ group = &channel->groups[i];
+ order = get_order(channel->group_size);
+ if (group->pg)
+ __free_pages(group->pg, order);
+ }
+}
+
+static int poch_channel_alloc_groups(struct channel_info *channel)
+{
+ unsigned long i;
+ unsigned long group_pages;
+ unsigned long header_pages;
+
+ group_pages = (channel->group_size / PAGE_SIZE) + 1;
+ header_pages = (channel->header_size / PAGE_SIZE) + 1;
+
+ for (i = 0; i < channel->group_count; i++) {
+ struct poch_group_info *group;
+ unsigned int order;
+ gfp_t gfp_mask;
+
+ group = &channel->groups[i];
+ order = get_order(channel->group_size);
+
+ /*
+ * __GFP_COMP is required here since we are going to
+ * perform non-linear mapping to userspace. For more
+ * information read the vm_insert_page() function
+ * comments.
+ */
+
+ gfp_mask = GFP_KERNEL | GFP_DMA32 | __GFP_ZERO;
+ group->pg = alloc_pages(gfp_mask, order);
+ if (!group->pg) {
+ poch_channel_free_groups(channel);
+ return -ENOMEM;
+ }
+
+ /* FIXME: This is the physical address not the bus
+ * address! This won't work in architectures that
+ * have an IOMMU. Can we use pci_map_single() for
+ * this?
+ */
+ group->dma_addr = page_to_pfn(group->pg) * PAGE_SIZE;
+ group->user_offset =
+ (header_pages + (i * group_pages)) * PAGE_SIZE;
+
+ printk(KERN_INFO PFX "%ld: user_offset: 0x%lx dma: 0x%x\n", i,
+ group->user_offset, group->dma_addr);
+ }
+
+ return 0;
+}
+
+static void channel_latch_attr(struct channel_info *channel)
+{
+ channel->group_count = atomic_read(&channel->sys_group_count);
+ channel->group_size = atomic_read(&channel->sys_group_size);
+ channel->block_size = atomic_read(&channel->sys_block_size);
+}
+
+/*
+ * Configure DMA group registers
+ */
+static void channel_dma_init(struct channel_info *channel)
+{
+ void __iomem *fpga = channel->fpga_iomem;
+ u32 group_regs_base;
+ u32 group_reg;
+ unsigned int page;
+ unsigned int group_in_page;
+ unsigned long i;
+ u32 block_size_reg;
+ u32 block_count_reg;
+ u32 group_count_reg;
+ u32 groups_per_int_reg;
+ u32 curr_pci_reg;
+
+ if (channel->chno == CHNO_RX_CHANNEL) {
+ group_regs_base = FPGA_RX_GROUP0_START_REG;
+ block_size_reg = FPGA_RX_BLOCK_SIZE_REG;
+ block_count_reg = FPGA_RX_BLOCK_COUNT_REG;
+ group_count_reg = FPGA_RX_GROUP_COUNT_REG;
+ groups_per_int_reg = FPGA_RX_GROUPS_PER_INT_REG;
+ curr_pci_reg = FPGA_RX_CURR_PCI_REG;
+ } else {
+ group_regs_base = FPGA_TX_GROUP0_START_REG;
+ block_size_reg = FPGA_TX_BLOCK_SIZE_REG;
+ block_count_reg = FPGA_TX_BLOCK_COUNT_REG;
+ group_count_reg = FPGA_TX_GROUP_COUNT_REG;
+ groups_per_int_reg = FPGA_TX_GROUPS_PER_INT_REG;
+ curr_pci_reg = FPGA_TX_CURR_PCI_REG;
+ }
+
+ printk(KERN_WARNING "block_size, group_size, group_count\n");
+ iowrite32(channel->block_size, fpga + block_size_reg);
+ iowrite32(channel->group_size / channel->block_size,
+ fpga + block_count_reg);
+ iowrite32(channel->group_count, fpga + group_count_reg);
+ /* FIXME: Hardcoded groups per int. Get it from sysfs? */
+ iowrite32(1, fpga + groups_per_int_reg);
+
+ /* Unlock PCI address? Not defined in the data sheet, but used
+ * in the reference code by Redrapids.
+ */
+ iowrite32(0x1, fpga + curr_pci_reg);
+
+ /* The DMA address page register is shared between the RX and
+ * TX channels, so acquire lock.
+ */
+ spin_lock(channel->iomem_lock);
+ for (i = 0; i < channel->group_count; i++) {
+ page = i / 32;
+ group_in_page = i % 32;
+
+ group_reg = group_regs_base + (group_in_page * 4);
+
+ iowrite32(page, fpga + FPGA_DMA_ADR_PAGE_REG);
+ iowrite32(channel->groups[i].dma_addr, fpga + group_reg);
+ }
+ for (i = 0; i < channel->group_count; i++) {
+ page = i / 32;
+ group_in_page = i % 32;
+
+ group_reg = group_regs_base + (group_in_page * 4);
+
+ iowrite32(page, fpga + FPGA_DMA_ADR_PAGE_REG);
+ printk(KERN_INFO PFX "%ld: read dma_addr: 0x%x\n", i,
+ ioread32(fpga + group_reg));
+ }
+ spin_unlock(channel->iomem_lock);
+
+}
+
+static int poch_channel_alloc_header(struct channel_info *channel)
+{
+ struct poch_cbuf_header *header = channel->header;
+ unsigned long group_offset_size;
+ unsigned long tot_group_offsets_size;
+
+ /* Allocate memory to hold header exported userspace */
+ group_offset_size = sizeof(header->group_offsets[0]);
+ tot_group_offsets_size = group_offset_size * channel->group_count;
+ channel->header_size = sizeof(*header) + tot_group_offsets_size;
+ channel->header_pg = alloc_pages(GFP_KERNEL | __GFP_ZERO,
+ get_order(channel->header_size));
+ if (!channel->header_pg)
+ return -ENOMEM;
+
+ channel->header = page_address(channel->header_pg);
+
+ return 0;
+}
+
+static void poch_channel_free_header(struct channel_info *channel)
+{
+ unsigned int order;
+
+ order = get_order(channel->header_size);
+ __free_pages(channel->header_pg, order);
+}
+
+static void poch_channel_init_header(struct channel_info *channel)
+{
+ int i;
+ struct poch_group_info *groups;
+ s32 *group_offsets;
+
+ channel->header->group_size_bytes = channel->group_size;
+ channel->header->group_count = channel->group_count;
+
+ spin_lock_init(&channel->group_offsets_lock);
+
+ group_offsets = channel->header->group_offsets;
+ groups = channel->groups;
+
+ for (i = 0; i < channel->group_count; i++) {
+ if (channel->dir == CHANNEL_DIR_RX)
+ group_offsets[i] = -1;
+ else
+ group_offsets[i] = groups[i].user_offset;
+ }
+}
+
+static void __poch_channel_clear_counters(struct channel_info *channel)
+{
+ channel->counters.pll_unlock = 0;
+ channel->counters.fifo_empty = 0;
+ channel->counters.fifo_overflow = 0;
+}
+
+static int poch_channel_init(struct channel_info *channel,
+ struct poch_dev *poch_dev)
+{
+ struct pci_dev *pdev = poch_dev->pci_dev;
+ struct device *dev = &pdev->dev;
+ unsigned long alloc_size;
+ int ret;
+
+ printk(KERN_WARNING "channel_latch_attr\n");
+
+ channel_latch_attr(channel);
+
+ channel->transfer = 0;
+
+ /* Allocate memory to hold group information. */
+ alloc_size = channel->group_count * sizeof(struct poch_group_info);
+ channel->groups = kzalloc(alloc_size, GFP_KERNEL);
+ if (!channel->groups) {
+ dev_err(dev, "error allocating memory for group info\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ printk(KERN_WARNING "poch_channel_alloc_groups\n");
+
+ ret = poch_channel_alloc_groups(channel);
+ if (ret) {
+ dev_err(dev, "error allocating groups of order %d\n",
+ get_order(channel->group_size));
+ goto out_free_group_info;
+ }
+
+ ret = poch_channel_alloc_header(channel);
+ if (ret) {
+ dev_err(dev, "error allocating user space header\n");
+ goto out_free_groups;
+ }
+
+ channel->fpga_iomem = poch_dev->fpga_iomem;
+ channel->bridge_iomem = poch_dev->bridge_iomem;
+ channel->iomem_lock = &poch_dev->iomem_lock;
+ spin_lock_init(&channel->counters_lock);
+
+ __poch_channel_clear_counters(channel);
+
+ printk(KERN_WARNING "poch_channel_init_header\n");
+
+ poch_channel_init_header(channel);
+
+ return 0;
+
+ out_free_groups:
+ poch_channel_free_groups(channel);
+ out_free_group_info:
+ kfree(channel->groups);
+ out:
+ return ret;
+}
+
+static int poch_wait_fpga_prog(void __iomem *bridge)
+{
+ unsigned long total_wait;
+ const unsigned long wait_period = 100;
+ /* FIXME: Get the actual timeout */
+ const unsigned long prog_timeo = 10000; /* 10 Seconds */
+ u32 card_power;
+
+ printk(KERN_WARNING "poch_wait_fpg_prog\n");
+
+ printk(KERN_INFO PFX "programming fpga ...\n");
+ total_wait = 0;
+ while (1) {
+ msleep(wait_period);
+ total_wait += wait_period;
+
+ card_power = ioread32(bridge + BRIDGE_CARD_POWER_REG);
+ if (card_power & BRIDGE_CARD_POWER_PROG_DONE) {
+ printk(KERN_INFO PFX "programming done\n");
+ return 0;
+ }
+ if (total_wait > prog_timeo) {
+ printk(KERN_ERR PFX
+ "timed out while programming FPGA\n");
+ return -EIO;
+ }
+ }
+}
+
+static void poch_card_power_off(struct poch_dev *poch_dev)
+{
+ void __iomem *bridge = poch_dev->bridge_iomem;
+ u32 card_power;
+
+ iowrite32(0, bridge + BRIDGE_INT_MASK_REG);
+ iowrite32(0, bridge + BRIDGE_DMA_GO_REG);
+
+ card_power = ioread32(bridge + BRIDGE_CARD_POWER_REG);
+ iowrite32(card_power & ~BRIDGE_CARD_POWER_EN,
+ bridge + BRIDGE_CARD_POWER_REG);
+}
+
+enum clk_src {
+ CLK_SRC_ON_BOARD,
+ CLK_SRC_EXTERNAL
+};
+
+static void poch_card_clock_on(void __iomem *fpga)
+{
+ /* FIXME: Get this data through sysfs? */
+ enum clk_src clk_src = CLK_SRC_ON_BOARD;
+
+ if (clk_src == CLK_SRC_ON_BOARD) {
+ iowrite32(FPGA_ADC_CLOCK_LOCAL_CLK | FPGA_ADC_CLOCK_CTL_OSC_EN,
+ fpga + FPGA_ADC_CLOCK_CTL_REG);
+ } else if (clk_src == CLK_SRC_EXTERNAL) {
+ iowrite32(FPGA_ADC_CLOCK_EXT_SAMP_CLK,
+ fpga + FPGA_ADC_CLOCK_CTL_REG);
+ }
+}
+
+static int poch_card_power_on(struct poch_dev *poch_dev)
+{
+ void __iomem *bridge = poch_dev->bridge_iomem;
+ void __iomem *fpga = poch_dev->fpga_iomem;
+
+ iowrite32(BRIDGE_CARD_POWER_EN, bridge + BRIDGE_CARD_POWER_REG);
+
+ if (poch_wait_fpga_prog(bridge) != 0) {
+ poch_card_power_off(poch_dev);
+ return -EIO;
+ }
+
+ poch_card_clock_on(fpga);
+
+ /* Sync to new clock, reset state machines, set DMA mode. */
+ iowrite32(FPGA_DOM_DCM_RESET | FPGA_DOM_SOFT_RESET
+ | FPGA_DOM_DUAL_M_SG_DMA, fpga + FPGA_DOM_REG);
+
+ /* FIXME: The time required for sync. needs to be tuned. */
+ msleep(1000);
+
+ return 0;
+}
+
+static void poch_channel_analog_on(struct channel_info *channel)
+{
+ void __iomem *fpga = channel->fpga_iomem;
+ u32 adc_dac_en;
+
+ spin_lock(channel->iomem_lock);
+ adc_dac_en = ioread32(fpga + FPGA_ADC_DAC_EN_REG);
+ switch (channel->chno) {
+ case CHNO_RX_CHANNEL:
+ iowrite32(adc_dac_en & ~FPGA_ADC_DAC_EN_ADC_OFF,
+ fpga + FPGA_ADC_DAC_EN_REG);
+ break;
+ case CHNO_TX_CHANNEL:
+ iowrite32(adc_dac_en & ~FPGA_ADC_DAC_EN_DAC_OFF,
+ fpga + FPGA_ADC_DAC_EN_REG);
+ break;
+ }
+ spin_unlock(channel->iomem_lock);
+}
+
+static int poch_open(struct inode *inode, struct file *filp)
+{
+ struct poch_dev *poch_dev;
+ struct channel_info *channel;
+ void __iomem *bridge;
+ void __iomem *fpga;
+ int chno;
+ int usage;
+ int ret;
+
+ poch_dev = container_of(inode->i_cdev, struct poch_dev, cdev);
+ bridge = poch_dev->bridge_iomem;
+ fpga = poch_dev->fpga_iomem;
+
+ chno = iminor(inode) % poch_dev->nchannels;
+ channel = &poch_dev->channels[chno];
+
+ if (!atomic_dec_and_test(&channel->free)) {
+ atomic_inc(&channel->free);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ usage = atomic_inc_return(&poch_dev->usage);
+
+ printk(KERN_WARNING "poch_card_power_on\n");
+
+ if (usage == 1) {
+ ret = poch_card_power_on(poch_dev);
+ if (ret)
+ goto out_dec_usage;
+ }
+
+ printk(KERN_INFO "CardBus Bridge Revision: %x\n",
+ ioread32(bridge + BRIDGE_REV_REG));
+ printk(KERN_INFO "CardBus Interface Revision: %x\n",
+ ioread32(fpga + FPGA_IFACE_REV_REG));
+
+ channel->chno = chno;
+ filp->private_data = channel;
+
+ printk(KERN_WARNING "poch_channel_init\n");
+
+ ret = poch_channel_init(channel, poch_dev);
+ if (ret)
+ goto out_power_off;
+
+ poch_channel_analog_on(channel);
+
+ printk(KERN_WARNING "channel_dma_init\n");
+
+ channel_dma_init(channel);
+
+ printk(KERN_WARNING "poch_channel_analog_on\n");
+
+ if (usage == 1) {
+ printk(KERN_WARNING "setting up DMA\n");
+
+ /* Initialize DMA Controller. */
+ iowrite32(FPGA_CAP_FIFO_REG, bridge + BRIDGE_STAT_2_REG);
+ iowrite32(FPGA_DMA_DESC_1_REG, bridge + BRIDGE_STAT_3_REG);
+
+ ioread32(fpga + FPGA_DMA_INT_STAT_REG);
+ ioread32(fpga + FPGA_INT_STAT_REG);
+ ioread32(bridge + BRIDGE_INT_STAT_REG);
+
+ /* Initialize Interrupts. FIXME: Enable temperature
+ * handling We are enabling both Tx and Rx channel
+ * interrupts here. Do we need to enable interrupts
+ * only for the current channel? Anyways we won't get
+ * the interrupt unless the DMA is activated.
+ */
+ iowrite32(BRIDGE_INT_FPGA, bridge + BRIDGE_INT_MASK_REG);
+ iowrite32(FPGA_INT_DMA_CORE
+ | FPGA_INT_PLL_UNLOCKED
+ | FPGA_INT_TX_FF_EMPTY
+ | FPGA_INT_RX_FF_EMPTY
+ | FPGA_INT_TX_FF_OVRFLW
+ | FPGA_INT_RX_FF_OVRFLW,
+ fpga + FPGA_INT_MASK_REG);
+ iowrite32(FPGA_DMA_INT_RX | FPGA_DMA_INT_TX,
+ fpga + FPGA_DMA_INT_MASK_REG);
+ }
+
+ if (channel->dir == CHANNEL_DIR_TX) {
+ /* Flush TX FIFO and output data from cardbus. */
+ iowrite32(FPGA_TX_CTL_FIFO_FLUSH
+ | FPGA_TX_CTL_OUTPUT_CARDBUS,
+ fpga + FPGA_TX_CTL_REG);
+ }
+
+ atomic_inc(&channel->inited);
+
+ return 0;
+
+ out_power_off:
+ if (usage == 1)
+ poch_card_power_off(poch_dev);
+ out_dec_usage:
+ atomic_dec(&poch_dev->usage);
+ atomic_inc(&channel->free);
+ out:
+ return ret;
+}
+
+static int poch_release(struct inode *inode, struct file *filp)
+{
+ struct channel_info *channel = filp->private_data;
+ struct poch_dev *poch_dev;
+ int usage;
+
+ poch_dev = container_of(inode->i_cdev, struct poch_dev, cdev);
+
+ usage = atomic_dec_return(&poch_dev->usage);
+ if (usage == 0) {
+ printk(KERN_WARNING "poch_card_power_off\n");
+ poch_card_power_off(poch_dev);
+ }
+
+ atomic_dec(&channel->inited);
+ poch_channel_free_header(channel);
+ poch_channel_free_groups(channel);
+ kfree(channel->groups);
+ atomic_inc(&channel->free);
+
+ return 0;
+}
+
+/*
+ * Map the header and the group buffers, to user space.
+ */
+static int poch_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct channel_info *channel = filp->private_data;
+
+ unsigned long start;
+ unsigned long size;
+
+ unsigned long group_pages;
+ unsigned long header_pages;
+ unsigned long total_group_pages;
+
+ int pg_num;
+ struct page *pg;
+
+ int i;
+ int ret;
+
+ printk(KERN_WARNING "poch_mmap\n");
+
+ if (vma->vm_pgoff) {
+ printk(KERN_WARNING PFX "page offset: %lu\n", vma->vm_pgoff);
+ return -EINVAL;
+ }
+
+ group_pages = (channel->group_size / PAGE_SIZE) + 1;
+ header_pages = (channel->header_size / PAGE_SIZE) + 1;
+ total_group_pages = group_pages * channel->group_count;
+
+ size = vma->vm_end - vma->vm_start;
+ if (size != (header_pages + total_group_pages) * PAGE_SIZE) {
+ printk(KERN_WARNING PFX "required %lu bytes\n", size);
+ return -EINVAL;
+ }
+
+ start = vma->vm_start;
+
+ /* FIXME: Cleanup required on failure? */
+ pg = channel->header_pg;
+ for (pg_num = 0; pg_num < header_pages; pg_num++, pg++) {
+ printk(KERN_DEBUG PFX "page_count: %d\n", page_count(pg));
+ printk(KERN_DEBUG PFX "%d: header: 0x%lx\n", pg_num, start);
+ ret = vm_insert_page(vma, start, pg);
+ if (ret) {
+ printk(KERN_DEBUG "vm_insert 1 failed at %lx\n", start);
+ return ret;
+ }
+ start += PAGE_SIZE;
+ }
+
+ for (i = 0; i < channel->group_count; i++) {
+ pg = channel->groups[i].pg;
+ for (pg_num = 0; pg_num < group_pages; pg_num++, pg++) {
+ printk(KERN_DEBUG PFX "%d: group %d: 0x%lx\n",
+ pg_num, i, start);
+ ret = vm_insert_page(vma, start, pg);
+ if (ret) {
+ printk(KERN_DEBUG PFX
+ "vm_insert 2 failed at %d\n", pg_num);
+ return ret;
+ }
+ start += PAGE_SIZE;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Check whether there is some group that the user space has not
+ * consumed yet. When the user space consumes a group, it sets it to
+ * -1. Cosuming could be reading data in case of RX and filling a
+ * buffer in case of TX.
+ */
+static int poch_channel_available(struct channel_info *channel)
+{
+ int i;
+
+ spin_lock_irq(&channel->group_offsets_lock);
+
+ for (i = 0; i < channel->group_count; i++) {
+ if (channel->dir == CHANNEL_DIR_RX
+ && channel->header->group_offsets[i] == -1) {
+ spin_unlock_irq(&channel->group_offsets_lock);
+ return 1;
+ }
+
+ if (channel->dir == CHANNEL_DIR_TX
+ && channel->header->group_offsets[i] != -1) {
+ spin_unlock_irq(&channel->group_offsets_lock);
+ return 1;
+ }
+ }
+
+ spin_unlock_irq(&channel->group_offsets_lock);
+
+ return 0;
+}
+
+static unsigned int poch_poll(struct file *filp, poll_table *pt)
+{
+ struct channel_info *channel = filp->private_data;
+ unsigned int ret = 0;
+
+ poll_wait(filp, &channel->wq, pt);
+
+ if (poch_channel_available(channel)) {
+ if (channel->dir == CHANNEL_DIR_RX)
+ ret = POLLIN | POLLRDNORM;
+ else
+ ret = POLLOUT | POLLWRNORM;
+ }
+
+ return ret;
+}
+
+static int poch_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct channel_info *channel = filp->private_data;
+ void __iomem *fpga = channel->fpga_iomem;
+ void __iomem *bridge = channel->bridge_iomem;
+ void __user *argp = (void __user *)arg;
+ struct vm_area_struct *vms;
+ struct poch_counters counters;
+ int ret;
+
+ switch (cmd) {
+ case POCH_IOC_TRANSFER_START:
+ switch (channel->chno) {
+ case CHNO_TX_CHANNEL:
+ printk(KERN_INFO PFX "ioctl: Tx start\n");
+ iowrite32(0x1, fpga + FPGA_TX_TRIGGER_REG);
+ iowrite32(0x1, fpga + FPGA_TX_ENABLE_REG);
+
+ /* FIXME: Does it make sense to do a DMA GO
+ * twice, once in Tx and once in Rx.
+ */
+ iowrite32(0x1, bridge + BRIDGE_DMA_GO_REG);
+ break;
+ case CHNO_RX_CHANNEL:
+ printk(KERN_INFO PFX "ioctl: Rx start\n");
+ iowrite32(0x1, fpga + FPGA_RX_ARM_REG);
+ iowrite32(0x1, bridge + BRIDGE_DMA_GO_REG);
+ break;
+ }
+ break;
+ case POCH_IOC_TRANSFER_STOP:
+ switch (channel->chno) {
+ case CHNO_TX_CHANNEL:
+ printk(KERN_INFO PFX "ioctl: Tx stop\n");
+ iowrite32(0x0, fpga + FPGA_TX_ENABLE_REG);
+ iowrite32(0x0, fpga + FPGA_TX_TRIGGER_REG);
+ iowrite32(0x0, bridge + BRIDGE_DMA_GO_REG);
+ break;
+ case CHNO_RX_CHANNEL:
+ printk(KERN_INFO PFX "ioctl: Rx stop\n");
+ iowrite32(0x0, fpga + FPGA_RX_ARM_REG);
+ iowrite32(0x0, bridge + BRIDGE_DMA_GO_REG);
+ break;
+ }
+ break;
+ case POCH_IOC_GET_COUNTERS:
+ if (access_ok(VERIFY_WRITE, argp, sizeof(struct poch_counters)))
+ return -EFAULT;
+
+ spin_lock_irq(&channel->counters_lock);
+ counters = channel->counters;
+ __poch_channel_clear_counters(channel);
+ spin_unlock_irq(&channel->counters_lock);
+
+ ret = copy_to_user(argp, &counters,
+ sizeof(struct poch_counters));
+ if (ret)
+ return ret;
+
+ break;
+ case POCH_IOC_SYNC_GROUP_FOR_USER:
+ case POCH_IOC_SYNC_GROUP_FOR_DEVICE:
+ vms = find_vma(current->mm, arg);
+ if (!vms)
+ /* Address not mapped. */
+ return -EINVAL;
+ if (vms->vm_file != filp)
+ /* Address mapped from different device/file. */
+ return -EINVAL;
+
+ flush_cache_range(vms, arg, arg + channel->group_size);
+ break;
+ }
+ return 0;
+}
+
+static struct file_operations poch_fops = {
+ .owner = THIS_MODULE,
+ .open = poch_open,
+ .release = poch_release,
+ .ioctl = poch_ioctl,
+ .poll = poch_poll,
+ .mmap = poch_mmap
+};
+
+static void poch_irq_dma(struct channel_info *channel)
+{
+ u32 prev_transfer;
+ u32 curr_transfer;
+ long groups_done;
+ unsigned long i, j;
+ struct poch_group_info *groups;
+ s32 *group_offsets;
+ u32 curr_group_reg;
+
+ if (!atomic_read(&channel->inited))
+ return;
+
+ prev_transfer = channel->transfer;
+
+ if (channel->chno == CHNO_RX_CHANNEL)
+ curr_group_reg = FPGA_RX_CURR_GROUP_REG;
+ else
+ curr_group_reg = FPGA_TX_CURR_GROUP_REG;
+
+ curr_transfer = ioread32(channel->fpga_iomem + curr_group_reg);
+
+ groups_done = curr_transfer - prev_transfer;
+ /* Check wrap over, and handle it. */
+ if (groups_done <= 0)
+ groups_done += channel->group_count;
+
+ group_offsets = channel->header->group_offsets;
+ groups = channel->groups;
+
+ spin_lock(&channel->group_offsets_lock);
+
+ for (i = 0; i < groups_done; i++) {
+ j = (prev_transfer + i) % channel->group_count;
+ if (channel->dir == CHANNEL_DIR_RX)
+ group_offsets[j] = -1;
+ else
+ group_offsets[j] = groups[j].user_offset;
+ }
+
+ spin_unlock(&channel->group_offsets_lock);
+
+ channel->transfer = curr_transfer;
+
+ wake_up_interruptible(&channel->wq);
+}
+
+static irqreturn_t poch_irq_handler(int irq, void *p)
+{
+ struct poch_dev *poch_dev = p;
+ void __iomem *bridge = poch_dev->bridge_iomem;
+ void __iomem *fpga = poch_dev->fpga_iomem;
+ struct channel_info *channel_rx = &poch_dev->channels[CHNO_RX_CHANNEL];
+ struct channel_info *channel_tx = &poch_dev->channels[CHNO_TX_CHANNEL];
+ u32 bridge_stat;
+ u32 fpga_stat;
+ u32 dma_stat;
+
+ bridge_stat = ioread32(bridge + BRIDGE_INT_STAT_REG);
+ fpga_stat = ioread32(fpga + FPGA_INT_STAT_REG);
+ dma_stat = ioread32(fpga + FPGA_DMA_INT_STAT_REG);
+
+ ioread32(fpga + FPGA_DMA_INT_STAT_REG);
+ ioread32(fpga + FPGA_INT_STAT_REG);
+ ioread32(bridge + BRIDGE_INT_STAT_REG);
+
+ if (bridge_stat & BRIDGE_INT_FPGA) {
+ if (fpga_stat & FPGA_INT_DMA_CORE) {
+ if (dma_stat & FPGA_DMA_INT_RX)
+ poch_irq_dma(channel_rx);
+ if (dma_stat & FPGA_DMA_INT_TX)
+ poch_irq_dma(channel_tx);
+ }
+ if (fpga_stat & FPGA_INT_PLL_UNLOCKED) {
+ channel_tx->counters.pll_unlock++;
+ channel_rx->counters.pll_unlock++;
+ if (printk_ratelimit())
+ printk(KERN_WARNING PFX "PLL unlocked\n");
+ }
+ if (fpga_stat & FPGA_INT_TX_FF_EMPTY)
+ channel_tx->counters.fifo_empty++;
+ if (fpga_stat & FPGA_INT_TX_FF_OVRFLW)
+ channel_tx->counters.fifo_overflow++;
+ if (fpga_stat & FPGA_INT_RX_FF_EMPTY)
+ channel_rx->counters.fifo_empty++;
+ if (fpga_stat & FPGA_INT_RX_FF_OVRFLW)
+ channel_rx->counters.fifo_overflow++;
+
+ /*
+ * FIXME: These errors should be notified through the
+ * poll interface as POLLERR.
+ */
+
+ /* Re-enable interrupts. */
+ iowrite32(BRIDGE_INT_FPGA, bridge + BRIDGE_INT_MASK_REG);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static void poch_class_dev_unregister(struct poch_dev *poch_dev, int id)
+{
+ int i, j;
+ int nattrs;
+ struct channel_info *channel;
+ dev_t devno;
+
+ if (poch_dev->dev == NULL)
+ return;
+
+ for (i = 0; i < poch_dev->nchannels; i++) {
+ channel = &poch_dev->channels[i];
+ devno = poch_first_dev + (id * poch_dev->nchannels) + i;
+
+ if (!channel->dev)
+ continue;
+
+ nattrs = sizeof(poch_class_attrs)/sizeof(poch_class_attrs[0]);
+ for (j = 0; j < nattrs; j++)
+ device_remove_file(channel->dev, poch_class_attrs[j]);
+
+ device_unregister(channel->dev);
+ }
+
+ device_unregister(poch_dev->dev);
+}
+
+static int __devinit poch_class_dev_register(struct poch_dev *poch_dev,
+ int id)
+{
+ struct device *dev = &poch_dev->pci_dev->dev;
+ int i, j;
+ int nattrs;
+ int ret;
+ struct channel_info *channel;
+ dev_t devno;
+
+ poch_dev->dev = device_create(poch_cls, &poch_dev->pci_dev->dev,
+ MKDEV(0, 0), NULL, "poch%d", id);
+ if (IS_ERR(poch_dev->dev)) {
+ dev_err(dev, "error creating parent class device");
+ ret = PTR_ERR(poch_dev->dev);
+ poch_dev->dev = NULL;
+ return ret;
+ }
+
+ for (i = 0; i < poch_dev->nchannels; i++) {
+ channel = &poch_dev->channels[i];
+
+ devno = poch_first_dev + (id * poch_dev->nchannels) + i;
+ channel->dev = device_create(poch_cls, poch_dev->dev, devno,
+ NULL, "ch%d", i);
+ if (IS_ERR(channel->dev)) {
+ dev_err(dev, "error creating channel class device");
+ ret = PTR_ERR(channel->dev);
+ channel->dev = NULL;
+ poch_class_dev_unregister(poch_dev, id);
+ return ret;
+ }
+
+ dev_set_drvdata(channel->dev, channel);
+ nattrs = sizeof(poch_class_attrs)/sizeof(poch_class_attrs[0]);
+ for (j = 0; j < nattrs; j++) {
+ ret = device_create_file(channel->dev,
+ poch_class_attrs[j]);
+ if (ret) {
+ dev_err(dev, "error creating attribute file");
+ poch_class_dev_unregister(poch_dev, id);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int __devinit poch_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+{
+ struct device *dev = &pdev->dev;
+ struct poch_dev *poch_dev;
+ struct uio_info *uio;
+ int ret;
+ int id;
+ int i;
+
+ poch_dev = kzalloc(sizeof(struct poch_dev), GFP_KERNEL);
+ if (!poch_dev) {
+ dev_err(dev, "error allocating priv. data memory\n");
+ return -ENOMEM;
+ }
+
+ poch_dev->pci_dev = pdev;
+ uio = &poch_dev->uio;
+
+ pci_set_drvdata(pdev, poch_dev);
+
+ spin_lock_init(&poch_dev->iomem_lock);
+
+ poch_dev->nchannels = POCH_NCHANNELS;
+ poch_dev->channels[CHNO_RX_CHANNEL].dir = CHANNEL_DIR_RX;
+ poch_dev->channels[CHNO_TX_CHANNEL].dir = CHANNEL_DIR_TX;
+
+ for (i = 0; i < poch_dev->nchannels; i++) {
+ init_waitqueue_head(&poch_dev->channels[i].wq);
+ atomic_set(&poch_dev->channels[i].free, 1);
+ atomic_set(&poch_dev->channels[i].inited, 0);
+ }
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(dev, "error enabling device\n");
+ goto out_free;
+ }
+
+ ret = pci_request_regions(pdev, "poch");
+ if (ret) {
+ dev_err(dev, "error requesting resources\n");
+ goto out_disable;
+ }
+
+ uio->mem[0].addr = pci_resource_start(pdev, 1);
+ if (!uio->mem[0].addr) {
+ dev_err(dev, "invalid BAR1\n");
+ ret = -ENODEV;
+ goto out_release;
+ }
+
+ uio->mem[0].size = pci_resource_len(pdev, 1);
+ uio->mem[0].memtype = UIO_MEM_PHYS;
+
+ uio->name = "poch";
+ uio->version = "0.0.1";
+ uio->irq = -1;
+ ret = uio_register_device(dev, uio);
+ if (ret) {
+ dev_err(dev, "error register UIO device: %d\n", ret);
+ goto out_release;
+ }
+
+ poch_dev->bridge_iomem = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (poch_dev->bridge_iomem == NULL) {
+ dev_err(dev, "error mapping bridge (bar0) registers\n");
+ ret = -ENOMEM;
+ goto out_uio_unreg;
+ }
+
+ poch_dev->fpga_iomem = ioremap(pci_resource_start(pdev, 1),
+ pci_resource_len(pdev, 1));
+ if (poch_dev->fpga_iomem == NULL) {
+ dev_err(dev, "error mapping fpga (bar1) registers\n");
+ ret = -ENOMEM;
+ goto out_bar0_unmap;
+ }
+
+ ret = request_irq(pdev->irq, poch_irq_handler, IRQF_SHARED,
+ dev->bus_id, poch_dev);
+ if (ret) {
+ dev_err(dev, "error requesting IRQ %u\n", pdev->irq);
+ ret = -ENOMEM;
+ goto out_bar1_unmap;
+ }
+
+ if (!idr_pre_get(&poch_ids, GFP_KERNEL)) {
+ dev_err(dev, "error allocating memory ids\n");
+ ret = -ENOMEM;
+ goto out_free_irq;
+ }
+
+ idr_get_new(&poch_ids, poch_dev, &id);
+ if (id >= MAX_POCH_CARDS) {
+ dev_err(dev, "minors exhausted\n");
+ ret = -EBUSY;
+ goto out_free_irq;
+ }
+
+ cdev_init(&poch_dev->cdev, &poch_fops);
+ poch_dev->cdev.owner = THIS_MODULE;
+ ret = cdev_add(&poch_dev->cdev,
+ poch_first_dev + (id * poch_dev->nchannels),
+ poch_dev->nchannels);
+ if (ret) {
+ dev_err(dev, "error register character device\n");
+ goto out_idr_remove;
+ }
+
+ ret = poch_class_dev_register(poch_dev, id);
+ if (ret)
+ goto out_cdev_del;
+
+ return 0;
+
+ out_cdev_del:
+ cdev_del(&poch_dev->cdev);
+ out_idr_remove:
+ idr_remove(&poch_ids, id);
+ out_free_irq:
+ free_irq(pdev->irq, poch_dev);
+ out_bar1_unmap:
+ iounmap(poch_dev->fpga_iomem);
+ out_bar0_unmap:
+ iounmap(poch_dev->bridge_iomem);
+ out_uio_unreg:
+ uio_unregister_device(uio);
+ out_release:
+ pci_release_regions(pdev);
+ out_disable:
+ pci_disable_device(pdev);
+ out_free:
+ kfree(poch_dev);
+ return ret;
+}
+
+/*
+ * FIXME: We are yet to handle the hot unplug case.
+ */
+static void poch_pci_remove(struct pci_dev *pdev)
+{
+ struct poch_dev *poch_dev = pci_get_drvdata(pdev);
+ struct uio_info *uio = &poch_dev->uio;
+ unsigned int minor = MINOR(poch_dev->cdev.dev);
+ unsigned int id = minor / poch_dev->nchannels;
+
+ /* FIXME: unmap fpga_iomem and bridge_iomem */
+
+ poch_class_dev_unregister(poch_dev, id);
+ cdev_del(&poch_dev->cdev);
+ idr_remove(&poch_ids, id);
+ free_irq(pdev->irq, poch_dev);
+ uio_unregister_device(uio);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ iounmap(uio->mem[0].internal_addr);
+
+ kfree(poch_dev);
+}
+
+static const struct pci_device_id poch_pci_ids[] /* __devinitconst */ = {
+ { PCI_DEVICE(PCI_VENDOR_ID_RRAPIDS,
+ PCI_DEVICE_ID_RRAPIDS_POCKET_CHANGE) },
+ { 0, }
+};
+
+static struct pci_driver poch_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = poch_pci_ids,
+ .probe = poch_pci_probe,
+ .remove = poch_pci_remove,
+};
+
+static int __init poch_init_module(void)
+{
+ int ret = 0;
+
+ ret = alloc_chrdev_region(&poch_first_dev, 0,
+ MAX_POCH_DEVICES, DRV_NAME);
+ if (ret) {
+ printk(KERN_ERR PFX "error allocating device no.");
+ return ret;
+ }
+
+ poch_cls = class_create(THIS_MODULE, "pocketchange");
+ if (IS_ERR(poch_cls)) {
+ ret = PTR_ERR(poch_cls);
+ goto out_unreg_chrdev;
+ }
+
+ ret = pci_register_driver(&poch_pci_driver);
+ if (ret) {
+ printk(KERN_ERR PFX "error register PCI device");
+ goto out_class_destroy;
+ }
+
+ return 0;
+
+ out_class_destroy:
+ class_destroy(poch_cls);
+
+ out_unreg_chrdev:
+ unregister_chrdev_region(poch_first_dev, MAX_POCH_DEVICES);
+
+ return ret;
+}
+
+static void __exit poch_exit_module(void)
+{
+ pci_unregister_driver(&poch_pci_driver);
+ class_destroy(poch_cls);
+ unregister_chrdev_region(poch_first_dev, MAX_POCH_DEVICES);
+}
+
+module_init(poch_init_module);
+module_exit(poch_exit_module);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/poch/poch.h b/drivers/staging/poch/poch.h
new file mode 100644
index 00000000000..51a2d145798
--- /dev/null
+++ b/drivers/staging/poch/poch.h
@@ -0,0 +1,29 @@
+/*
+ * User-space DMA and UIO based Redrapids Pocket Change CardBus driver
+ *
+ * Copyright 2008 Vijay Kumar <vijaykumar@bravegnu.org>
+ *
+ * Part of userspace API. Should be moved to a header file in
+ * include/linux for final version.
+ *
+ */
+struct poch_cbuf_header {
+ __s32 group_size_bytes;
+ __s32 group_count;
+ __s32 group_offsets[0];
+};
+
+struct poch_counters {
+ __u32 fifo_empty;
+ __u32 fifo_overflow;
+ __u32 pll_unlock;
+};
+
+#define POCH_IOC_NUM '9'
+
+#define POCH_IOC_TRANSFER_START _IO(POCH_IOC_NUM, 0)
+#define POCH_IOC_TRANSFER_STOP _IO(POCH_IOC_NUM, 1)
+#define POCH_IOC_GET_COUNTERS _IOR(POCH_IOC_NUM, 2, \
+ struct poch_counters)
+#define POCH_IOC_SYNC_GROUP_FOR_USER _IO(POCH_IOC_NUM, 3)
+#define POCH_IOC_SYNC_GROUP_FOR_DEVICE _IO(POCH_IOC_NUM, 4)
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index b61ac4b2db9..8fa9490b3e2 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -54,7 +54,6 @@
* IS-NIC driver.
*/
-#include <linux/version.h>
#define SLIC_DUMP_ENABLED 0
#define KLUDGE_FOR_4GB_BOUNDARY 1
@@ -96,17 +95,9 @@
#include <linux/moduleparam.h>
#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/dma-mapping.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
-#include <linux/skbuff.h>
-#include <linux/string.h>
#include <asm/unaligned.h>
#include <linux/ethtool.h>
@@ -275,7 +266,6 @@ static void slic_dbg_register_trace(struct adapter *adapter,
card->reg_value[i], card->reg_valueh[i]);
}
}
-}
#endif
static void slic_init_adapter(struct net_device *netdev,
@@ -606,6 +596,7 @@ static void __devexit slic_entry_remove(struct pci_dev *pcidev)
uint mmio_len = 0;
struct adapter *adapter = (struct adapter *) netdev_priv(dev);
struct sliccard *card;
+ struct mcast_address *mcaddr, *mlist;
ASSERT(adapter);
DBG_MSG("slicoss: %s ENTER dev[%p] adapter[%p]\n", __func__, dev,
@@ -625,6 +616,13 @@ static void __devexit slic_entry_remove(struct pci_dev *pcidev)
DBG_MSG("slicoss: %s iounmap dev->base_addr[%x]\n", __func__,
(uint) dev->base_addr);
iounmap((void __iomem *)dev->base_addr);
+ /* free multicast addresses */
+ mlist = adapter->mcastaddrs;
+ while (mlist) {
+ mcaddr = mlist;
+ mlist = mlist->next;
+ kfree(mcaddr);
+ }
ASSERT(adapter->card);
card = adapter->card;
ASSERT(card->adapters_allocated);
diff --git a/drivers/staging/sxg/Kconfig b/drivers/staging/sxg/Kconfig
index 1ae35080660..6e6cf0b9ef9 100644
--- a/drivers/staging/sxg/Kconfig
+++ b/drivers/staging/sxg/Kconfig
@@ -1,6 +1,7 @@
config SXG
tristate "Alacritech SLIC Technology Non-Accelerated 10Gbe support"
depends on PCI && NETDEV_10000
+ depends on X86
default n
help
This driver supports the Alacritech SLIC Technology Non-Accelerated
diff --git a/drivers/staging/sxg/README b/drivers/staging/sxg/README
index 4d1ddbe4c33..d514d184880 100644
--- a/drivers/staging/sxg/README
+++ b/drivers/staging/sxg/README
@@ -7,6 +7,7 @@ TODO:
- remove wrappers
- checkpatch.pl cleanups
- new functionality that the card needs
+ - remove reliance on x86
Please send patches to:
Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c
index 6ccbee875ab..5272a18e204 100644
--- a/drivers/staging/sxg/sxg.c
+++ b/drivers/staging/sxg/sxg.c
@@ -112,12 +112,16 @@ static bool sxg_mac_filter(p_adapter_t adapter,
static struct net_device_stats *sxg_get_stats(p_net_device dev);
#endif
+#define XXXTODO 0
+
+#if XXXTODO
static int sxg_mac_set_address(p_net_device dev, void *ptr);
+static void sxg_mcast_set_list(p_net_device dev);
+#endif
static void sxg_adapter_set_hwaddr(p_adapter_t adapter);
static void sxg_unmap_mmio_space(p_adapter_t adapter);
-static void sxg_mcast_set_mask(p_adapter_t adapter);
static int sxg_initialize_adapter(p_adapter_t adapter);
static void sxg_stock_rcv_buffers(p_adapter_t adapter);
@@ -132,9 +136,6 @@ static int sxg_write_mdio_reg(p_adapter_t adapter,
u32 DevAddr, u32 RegAddr, u32 Value);
static int sxg_read_mdio_reg(p_adapter_t adapter,
u32 DevAddr, u32 RegAddr, u32 *pValue);
-static void sxg_mcast_set_list(p_net_device dev);
-
-#define XXXTODO 0
static unsigned int sxg_first_init = 1;
static char *sxg_banner =
@@ -202,7 +203,7 @@ static void sxg_init_driver(void)
{
if (sxg_first_init) {
DBG_ERROR("sxg: %s sxg_first_init set jiffies[%lx]\n",
- __FUNCTION__, jiffies);
+ __func__, jiffies);
sxg_first_init = 0;
spin_lock_init(&sxg_global.driver_lock);
}
@@ -223,7 +224,7 @@ static void sxg_dbg_macaddrs(p_adapter_t adapter)
return;
}
-// SXG Globals
+/* SXG Globals */
static SXG_DRIVER SxgDriver;
#ifdef ATKDBG
@@ -250,7 +251,7 @@ static bool sxg_download_microcode(p_adapter_t adapter, SXG_UCODE_SEL UcodeSel)
u32 ThisSectionSize;
u32 *Instruction = NULL;
u32 BaseAddress, AddressOffset, Address;
-// u32 Failure;
+/* u32 Failure; */
u32 ValueRead;
u32 i;
u32 numSections = 0;
@@ -259,10 +260,10 @@ static bool sxg_download_microcode(p_adapter_t adapter, SXG_UCODE_SEL UcodeSel)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DnldUcod",
adapter, 0, 0, 0);
- DBG_ERROR("sxg: %s ENTER\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s ENTER\n", __func__);
switch (UcodeSel) {
- case SXG_UCODE_SAHARA: // Sahara operational ucode
+ case SXG_UCODE_SAHARA: /* Sahara operational ucode */
numSections = SNumSections;
for (i = 0; i < numSections; i++) {
sectionSize[i] = SSectionSize[i];
@@ -276,13 +277,13 @@ static bool sxg_download_microcode(p_adapter_t adapter, SXG_UCODE_SEL UcodeSel)
}
DBG_ERROR("sxg: RESET THE CARD\n");
- // First, reset the card
+ /* First, reset the card */
WRITE_REG(HwRegs->Reset, 0xDEAD, FLUSH);
- // Download each section of the microcode as specified in
- // its download file. The *download.c file is generated using
- // the saharaobjtoc facility which converts the metastep .obj
- // file to a .c file which contains a two dimentional array.
+ /* Download each section of the microcode as specified in */
+ /* its download file. The *download.c file is generated using */
+ /* the saharaobjtoc facility which converts the metastep .obj */
+ /* file to a .c file which contains a two dimentional array. */
for (Section = 0; Section < numSections; Section++) {
DBG_ERROR("sxg: SECTION # %d\n", Section);
switch (UcodeSel) {
@@ -294,35 +295,35 @@ static bool sxg_download_microcode(p_adapter_t adapter, SXG_UCODE_SEL UcodeSel)
break;
}
BaseAddress = sectionStart[Section];
- ThisSectionSize = sectionSize[Section] / 12; // Size in instructions
+ ThisSectionSize = sectionSize[Section] / 12; /* Size in instructions */
for (AddressOffset = 0; AddressOffset < ThisSectionSize;
AddressOffset++) {
Address = BaseAddress + AddressOffset;
ASSERT((Address & ~MICROCODE_ADDRESS_MASK) == 0);
- // Write instruction bits 31 - 0
+ /* Write instruction bits 31 - 0 */
WRITE_REG(HwRegs->UcodeDataLow, *Instruction, FLUSH);
- // Write instruction bits 63-32
+ /* Write instruction bits 63-32 */
WRITE_REG(HwRegs->UcodeDataMiddle, *(Instruction + 1),
FLUSH);
- // Write instruction bits 95-64
+ /* Write instruction bits 95-64 */
WRITE_REG(HwRegs->UcodeDataHigh, *(Instruction + 2),
FLUSH);
- // Write instruction address with the WRITE bit set
+ /* Write instruction address with the WRITE bit set */
WRITE_REG(HwRegs->UcodeAddr,
(Address | MICROCODE_ADDRESS_WRITE), FLUSH);
- // Sahara bug in the ucode download logic - the write to DataLow
- // for the next instruction could get corrupted. To avoid this,
- // write to DataLow again for this instruction (which may get
- // corrupted, but it doesn't matter), then increment the address
- // and write the data for the next instruction to DataLow. That
- // write should succeed.
+ /* Sahara bug in the ucode download logic - the write to DataLow */
+ /* for the next instruction could get corrupted. To avoid this, */
+ /* write to DataLow again for this instruction (which may get */
+ /* corrupted, but it doesn't matter), then increment the address */
+ /* and write the data for the next instruction to DataLow. That */
+ /* write should succeed. */
WRITE_REG(HwRegs->UcodeDataLow, *Instruction, TRUE);
- // Advance 3 u32S to start of next instruction
+ /* Advance 3 u32S to start of next instruction */
Instruction += 3;
}
}
- // Now repeat the entire operation reading the instruction back and
- // checking for parity errors
+ /* Now repeat the entire operation reading the instruction back and */
+ /* checking for parity errors */
for (Section = 0; Section < numSections; Section++) {
DBG_ERROR("sxg: check SECTION # %d\n", Section);
switch (UcodeSel) {
@@ -334,74 +335,74 @@ static bool sxg_download_microcode(p_adapter_t adapter, SXG_UCODE_SEL UcodeSel)
break;
}
BaseAddress = sectionStart[Section];
- ThisSectionSize = sectionSize[Section] / 12; // Size in instructions
+ ThisSectionSize = sectionSize[Section] / 12; /* Size in instructions */
for (AddressOffset = 0; AddressOffset < ThisSectionSize;
AddressOffset++) {
Address = BaseAddress + AddressOffset;
- // Write the address with the READ bit set
+ /* Write the address with the READ bit set */
WRITE_REG(HwRegs->UcodeAddr,
(Address | MICROCODE_ADDRESS_READ), FLUSH);
- // Read it back and check parity bit.
+ /* Read it back and check parity bit. */
READ_REG(HwRegs->UcodeAddr, ValueRead);
if (ValueRead & MICROCODE_ADDRESS_PARITY) {
DBG_ERROR("sxg: %s PARITY ERROR\n",
- __FUNCTION__);
+ __func__);
- return (FALSE); // Parity error
+ return (FALSE); /* Parity error */
}
ASSERT((ValueRead & MICROCODE_ADDRESS_MASK) == Address);
- // Read the instruction back and compare
+ /* Read the instruction back and compare */
READ_REG(HwRegs->UcodeDataLow, ValueRead);
if (ValueRead != *Instruction) {
DBG_ERROR("sxg: %s MISCOMPARE LOW\n",
- __FUNCTION__);
- return (FALSE); // Miscompare
+ __func__);
+ return (FALSE); /* Miscompare */
}
READ_REG(HwRegs->UcodeDataMiddle, ValueRead);
if (ValueRead != *(Instruction + 1)) {
DBG_ERROR("sxg: %s MISCOMPARE MIDDLE\n",
- __FUNCTION__);
- return (FALSE); // Miscompare
+ __func__);
+ return (FALSE); /* Miscompare */
}
READ_REG(HwRegs->UcodeDataHigh, ValueRead);
if (ValueRead != *(Instruction + 2)) {
DBG_ERROR("sxg: %s MISCOMPARE HIGH\n",
- __FUNCTION__);
- return (FALSE); // Miscompare
+ __func__);
+ return (FALSE); /* Miscompare */
}
- // Advance 3 u32S to start of next instruction
+ /* Advance 3 u32S to start of next instruction */
Instruction += 3;
}
}
- // Everything OK, Go.
+ /* Everything OK, Go. */
WRITE_REG(HwRegs->UcodeAddr, MICROCODE_ADDRESS_GO, FLUSH);
- // Poll the CardUp register to wait for microcode to initialize
- // Give up after 10,000 attemps (500ms).
+ /* Poll the CardUp register to wait for microcode to initialize */
+ /* Give up after 10,000 attemps (500ms). */
for (i = 0; i < 10000; i++) {
udelay(50);
READ_REG(adapter->UcodeRegs[0].CardUp, ValueRead);
if (ValueRead == 0xCAFE) {
- DBG_ERROR("sxg: %s BOO YA 0xCAFE\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s BOO YA 0xCAFE\n", __func__);
break;
}
}
if (i == 10000) {
- DBG_ERROR("sxg: %s TIMEOUT\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s TIMEOUT\n", __func__);
- return (FALSE); // Timeout
+ return (FALSE); /* Timeout */
}
- // Now write the LoadSync register. This is used to
- // synchronize with the card so it can scribble on the memory
- // that contained 0xCAFE from the "CardUp" step above
+ /* Now write the LoadSync register. This is used to */
+ /* synchronize with the card so it can scribble on the memory */
+ /* that contained 0xCAFE from the "CardUp" step above */
if (UcodeSel == SXG_UCODE_SAHARA) {
WRITE_REG(adapter->UcodeRegs[0].LoadSync, 0, FLUSH);
}
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDnldUcd",
adapter, 0, 0, 0);
- DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s EXIT\n", __func__);
return (TRUE);
}
@@ -420,29 +421,29 @@ static int sxg_allocate_resources(p_adapter_t adapter)
int status;
u32 i;
u32 RssIds, IsrCount;
-// PSXG_XMT_RING XmtRing;
-// PSXG_RCV_RING RcvRing;
+/* PSXG_XMT_RING XmtRing; */
+/* PSXG_RCV_RING RcvRing; */
- DBG_ERROR("%s ENTER\n", __FUNCTION__);
+ DBG_ERROR("%s ENTER\n", __func__);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocRes",
adapter, 0, 0, 0);
- // Windows tells us how many CPUs it plans to use for
- // RSS
+ /* Windows tells us how many CPUs it plans to use for */
+ /* RSS */
RssIds = SXG_RSS_CPU_COUNT(adapter);
IsrCount = adapter->MsiEnabled ? RssIds : 1;
- DBG_ERROR("%s Setup the spinlocks\n", __FUNCTION__);
+ DBG_ERROR("%s Setup the spinlocks\n", __func__);
- // Allocate spinlocks and initialize listheads first.
+ /* Allocate spinlocks and initialize listheads first. */
spin_lock_init(&adapter->RcvQLock);
spin_lock_init(&adapter->SglQLock);
spin_lock_init(&adapter->XmtZeroLock);
spin_lock_init(&adapter->Bit64RegLock);
spin_lock_init(&adapter->AdapterLock);
- DBG_ERROR("%s Setup the lists\n", __FUNCTION__);
+ DBG_ERROR("%s Setup the lists\n", __func__);
InitializeListHead(&adapter->FreeRcvBuffers);
InitializeListHead(&adapter->FreeRcvBlocks);
@@ -450,39 +451,39 @@ static int sxg_allocate_resources(p_adapter_t adapter)
InitializeListHead(&adapter->FreeSglBuffers);
InitializeListHead(&adapter->AllSglBuffers);
- // Mark these basic allocations done. This flags essentially
- // tells the SxgFreeResources routine that it can grab spinlocks
- // and reference listheads.
+ /* Mark these basic allocations done. This flags essentially */
+ /* tells the SxgFreeResources routine that it can grab spinlocks */
+ /* and reference listheads. */
adapter->BasicAllocations = TRUE;
- // Main allocation loop. Start with the maximum supported by
- // the microcode and back off if memory allocation
- // fails. If we hit a minimum, fail.
+ /* Main allocation loop. Start with the maximum supported by */
+ /* the microcode and back off if memory allocation */
+ /* fails. If we hit a minimum, fail. */
for (;;) {
- DBG_ERROR("%s Allocate XmtRings size[%lx]\n", __FUNCTION__,
- (sizeof(SXG_XMT_RING) * 1));
+ DBG_ERROR("%s Allocate XmtRings size[%x]\n", __func__,
+ (unsigned int)(sizeof(SXG_XMT_RING) * 1));
- // Start with big items first - receive and transmit rings. At the moment
- // I'm going to keep the ring size fixed and adjust the number of
- // TCBs if we fail. Later we might consider reducing the ring size as well..
+ /* Start with big items first - receive and transmit rings. At the moment */
+ /* I'm going to keep the ring size fixed and adjust the number of */
+ /* TCBs if we fail. Later we might consider reducing the ring size as well.. */
adapter->XmtRings = pci_alloc_consistent(adapter->pcidev,
sizeof(SXG_XMT_RING) *
1,
&adapter->PXmtRings);
- DBG_ERROR("%s XmtRings[%p]\n", __FUNCTION__, adapter->XmtRings);
+ DBG_ERROR("%s XmtRings[%p]\n", __func__, adapter->XmtRings);
if (!adapter->XmtRings) {
goto per_tcb_allocation_failed;
}
memset(adapter->XmtRings, 0, sizeof(SXG_XMT_RING) * 1);
- DBG_ERROR("%s Allocate RcvRings size[%lx]\n", __FUNCTION__,
- (sizeof(SXG_RCV_RING) * 1));
+ DBG_ERROR("%s Allocate RcvRings size[%x]\n", __func__,
+ (unsigned int)(sizeof(SXG_RCV_RING) * 1));
adapter->RcvRings =
pci_alloc_consistent(adapter->pcidev,
sizeof(SXG_RCV_RING) * 1,
&adapter->PRcvRings);
- DBG_ERROR("%s RcvRings[%p]\n", __FUNCTION__, adapter->RcvRings);
+ DBG_ERROR("%s RcvRings[%p]\n", __func__, adapter->RcvRings);
if (!adapter->RcvRings) {
goto per_tcb_allocation_failed;
}
@@ -490,7 +491,7 @@ static int sxg_allocate_resources(p_adapter_t adapter)
break;
per_tcb_allocation_failed:
- // an allocation failed. Free any successful allocations.
+ /* an allocation failed. Free any successful allocations. */
if (adapter->XmtRings) {
pci_free_consistent(adapter->pcidev,
sizeof(SXG_XMT_RING) * 4096,
@@ -505,22 +506,22 @@ static int sxg_allocate_resources(p_adapter_t adapter)
adapter->PRcvRings);
adapter->RcvRings = NULL;
}
- // Loop around and try again....
+ /* Loop around and try again.... */
}
- DBG_ERROR("%s Initialize RCV ZERO and XMT ZERO rings\n", __FUNCTION__);
- // Initialize rcv zero and xmt zero rings
+ DBG_ERROR("%s Initialize RCV ZERO and XMT ZERO rings\n", __func__);
+ /* Initialize rcv zero and xmt zero rings */
SXG_INITIALIZE_RING(adapter->RcvRingZeroInfo, SXG_RCV_RING_SIZE);
SXG_INITIALIZE_RING(adapter->XmtRingZeroInfo, SXG_XMT_RING_SIZE);
- // Sanity check receive data structure format
+ /* Sanity check receive data structure format */
ASSERT((adapter->ReceiveBufferSize == SXG_RCV_DATA_BUFFER_SIZE) ||
(adapter->ReceiveBufferSize == SXG_RCV_JUMBO_BUFFER_SIZE));
ASSERT(sizeof(SXG_RCV_DESCRIPTOR_BLOCK) ==
SXG_RCV_DESCRIPTOR_BLOCK_SIZE);
- // Allocate receive data buffers. We allocate a block of buffers and
- // a corresponding descriptor block at once. See sxghw.h:SXG_RCV_BLOCK
+ /* Allocate receive data buffers. We allocate a block of buffers and */
+ /* a corresponding descriptor block at once. See sxghw.h:SXG_RCV_BLOCK */
for (i = 0; i < SXG_INITIAL_RCV_DATA_BUFFERS;
i += SXG_RCV_DESCRIPTORS_PER_BLOCK) {
sxg_allocate_buffer_memory(adapter,
@@ -528,8 +529,8 @@ static int sxg_allocate_resources(p_adapter_t adapter)
ReceiveBufferSize),
SXG_BUFFER_TYPE_RCV);
}
- // NBL resource allocation can fail in the 'AllocateComplete' routine, which
- // doesn't return status. Make sure we got the number of buffers we requested
+ /* NBL resource allocation can fail in the 'AllocateComplete' routine, which */
+ /* doesn't return status. Make sure we got the number of buffers we requested */
if (adapter->FreeRcvBufferCount < SXG_INITIAL_RCV_DATA_BUFFERS) {
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF6",
adapter, adapter->FreeRcvBufferCount, SXG_MAX_ENTRIES,
@@ -537,17 +538,17 @@ static int sxg_allocate_resources(p_adapter_t adapter)
return (STATUS_RESOURCES);
}
- DBG_ERROR("%s Allocate EventRings size[%lx]\n", __FUNCTION__,
- (sizeof(SXG_EVENT_RING) * RssIds));
+ DBG_ERROR("%s Allocate EventRings size[%x]\n", __func__,
+ (unsigned int)(sizeof(SXG_EVENT_RING) * RssIds));
- // Allocate event queues.
+ /* Allocate event queues. */
adapter->EventRings = pci_alloc_consistent(adapter->pcidev,
sizeof(SXG_EVENT_RING) *
RssIds,
&adapter->PEventRings);
if (!adapter->EventRings) {
- // Caller will call SxgFreeAdapter to clean up above allocations
+ /* Caller will call SxgFreeAdapter to clean up above allocations */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF8",
adapter, SXG_MAX_ENTRIES, 0, 0);
status = STATUS_RESOURCES;
@@ -555,12 +556,12 @@ static int sxg_allocate_resources(p_adapter_t adapter)
}
memset(adapter->EventRings, 0, sizeof(SXG_EVENT_RING) * RssIds);
- DBG_ERROR("%s Allocate ISR size[%x]\n", __FUNCTION__, IsrCount);
- // Allocate ISR
+ DBG_ERROR("%s Allocate ISR size[%x]\n", __func__, IsrCount);
+ /* Allocate ISR */
adapter->Isr = pci_alloc_consistent(adapter->pcidev,
IsrCount, &adapter->PIsr);
if (!adapter->Isr) {
- // Caller will call SxgFreeAdapter to clean up above allocations
+ /* Caller will call SxgFreeAdapter to clean up above allocations */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF9",
adapter, SXG_MAX_ENTRIES, 0, 0);
status = STATUS_RESOURCES;
@@ -568,10 +569,10 @@ static int sxg_allocate_resources(p_adapter_t adapter)
}
memset(adapter->Isr, 0, sizeof(u32) * IsrCount);
- DBG_ERROR("%s Allocate shared XMT ring zero index location size[%lx]\n",
- __FUNCTION__, sizeof(u32));
+ DBG_ERROR("%s Allocate shared XMT ring zero index location size[%x]\n",
+ __func__, (unsigned int)sizeof(u32));
- // Allocate shared XMT ring zero index location
+ /* Allocate shared XMT ring zero index location */
adapter->XmtRingZeroIndex = pci_alloc_consistent(adapter->pcidev,
sizeof(u32),
&adapter->
@@ -587,7 +588,7 @@ static int sxg_allocate_resources(p_adapter_t adapter)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlcResS",
adapter, SXG_MAX_ENTRIES, 0, 0);
- DBG_ERROR("%s EXIT\n", __FUNCTION__);
+ DBG_ERROR("%s EXIT\n", __func__);
return (STATUS_SUCCESS);
}
@@ -606,17 +607,17 @@ static void sxg_config_pci(struct pci_dev *pcidev)
u16 new_command;
pci_read_config_word(pcidev, PCI_COMMAND, &pci_command);
- DBG_ERROR("sxg: %s PCI command[%4.4x]\n", __FUNCTION__, pci_command);
- // Set the command register
- new_command = pci_command | (PCI_COMMAND_MEMORY | // Memory Space Enable
- PCI_COMMAND_MASTER | // Bus master enable
- PCI_COMMAND_INVALIDATE | // Memory write and invalidate
- PCI_COMMAND_PARITY | // Parity error response
- PCI_COMMAND_SERR | // System ERR
- PCI_COMMAND_FAST_BACK); // Fast back-to-back
+ DBG_ERROR("sxg: %s PCI command[%4.4x]\n", __func__, pci_command);
+ /* Set the command register */
+ new_command = pci_command | (PCI_COMMAND_MEMORY | /* Memory Space Enable */
+ PCI_COMMAND_MASTER | /* Bus master enable */
+ PCI_COMMAND_INVALIDATE | /* Memory write and invalidate */
+ PCI_COMMAND_PARITY | /* Parity error response */
+ PCI_COMMAND_SERR | /* System ERR */
+ PCI_COMMAND_FAST_BACK); /* Fast back-to-back */
if (pci_command != new_command) {
DBG_ERROR("%s -- Updating PCI COMMAND register %4.4x->%4.4x.\n",
- __FUNCTION__, pci_command, new_command);
+ __func__, pci_command, new_command);
pci_write_config_word(pcidev, PCI_COMMAND, new_command);
}
}
@@ -634,9 +635,9 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
ulong mmio_len = 0;
DBG_ERROR("sxg: %s 2.6 VERSION ENTER jiffies[%lx] cpu %d\n",
- __FUNCTION__, jiffies, smp_processor_id());
+ __func__, jiffies, smp_processor_id());
- // Initialize trace buffer
+ /* Initialize trace buffer */
#ifdef ATKDBG
SxgTraceBuffer = &LSxgTraceBuffer;
SXG_TRACE_INIT(SxgTraceBuffer, TRACE_NOISY);
@@ -701,11 +702,11 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
mmio_start, mmio_len);
memmapped_ioaddr = ioremap(mmio_start, mmio_len);
- DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __FUNCTION__,
+ DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __func__,
memmapped_ioaddr);
if (!memmapped_ioaddr) {
DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n",
- __FUNCTION__, mmio_len, mmio_start);
+ __func__, mmio_len, mmio_start);
goto err_out_free_mmio_region;
}
@@ -727,7 +728,7 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
memmapped_ioaddr);
if (!memmapped_ioaddr) {
DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n",
- __FUNCTION__, mmio_len, mmio_start);
+ __func__, mmio_len, mmio_start);
goto err_out_free_mmio_region;
}
@@ -738,13 +739,13 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
adapter->UcodeRegs = (void *)memmapped_ioaddr;
adapter->State = SXG_STATE_INITIALIZING;
- // Maintain a list of all adapters anchored by
- // the global SxgDriver structure.
+ /* Maintain a list of all adapters anchored by */
+ /* the global SxgDriver structure. */
adapter->Next = SxgDriver.Adapters;
SxgDriver.Adapters = adapter;
adapter->AdapterID = ++SxgDriver.AdapterID;
- // Initialize CRC table used to determine multicast hash
+ /* Initialize CRC table used to determine multicast hash */
sxg_mcast_init_crc32();
adapter->JumboEnabled = FALSE;
@@ -757,18 +758,18 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
adapter->ReceiveBufferSize = SXG_RCV_DATA_BUFFER_SIZE;
}
-// status = SXG_READ_EEPROM(adapter);
-// if (!status) {
-// goto sxg_init_bad;
-// }
+/* status = SXG_READ_EEPROM(adapter); */
+/* if (!status) { */
+/* goto sxg_init_bad; */
+/* } */
- DBG_ERROR("sxg: %s ENTER sxg_config_pci\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s ENTER sxg_config_pci\n", __func__);
sxg_config_pci(pcidev);
- DBG_ERROR("sxg: %s EXIT sxg_config_pci\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s EXIT sxg_config_pci\n", __func__);
- DBG_ERROR("sxg: %s ENTER sxg_init_driver\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s ENTER sxg_init_driver\n", __func__);
sxg_init_driver();
- DBG_ERROR("sxg: %s EXIT sxg_init_driver\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s EXIT sxg_init_driver\n", __func__);
adapter->vendid = pci_tbl_entry->vendor;
adapter->devid = pci_tbl_entry->device;
@@ -780,23 +781,23 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
adapter->irq = pcidev->irq;
adapter->next_netdevice = head_netdevice;
head_netdevice = netdev;
-// adapter->chipid = chip_idx;
- adapter->port = 0; //adapter->functionnumber;
+/* adapter->chipid = chip_idx; */
+ adapter->port = 0; /*adapter->functionnumber; */
adapter->cardindex = adapter->port;
- // Allocate memory and other resources
- DBG_ERROR("sxg: %s ENTER sxg_allocate_resources\n", __FUNCTION__);
+ /* Allocate memory and other resources */
+ DBG_ERROR("sxg: %s ENTER sxg_allocate_resources\n", __func__);
status = sxg_allocate_resources(adapter);
DBG_ERROR("sxg: %s EXIT sxg_allocate_resources status %x\n",
- __FUNCTION__, status);
+ __func__, status);
if (status != STATUS_SUCCESS) {
goto err_out_unmap;
}
- DBG_ERROR("sxg: %s ENTER sxg_download_microcode\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s ENTER sxg_download_microcode\n", __func__);
if (sxg_download_microcode(adapter, SXG_UCODE_SAHARA)) {
DBG_ERROR("sxg: %s ENTER sxg_adapter_set_hwaddr\n",
- __FUNCTION__);
+ __func__);
sxg_adapter_set_hwaddr(adapter);
} else {
adapter->state = ADAPT_FAIL;
@@ -819,7 +820,7 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
#endif
strcpy(netdev->name, "eth%d");
-// strcpy(netdev->name, pci_name(pcidev));
+/* strcpy(netdev->name, pci_name(pcidev)); */
if ((err = register_netdev(netdev))) {
DBG_ERROR("Cannot register net device, aborting. %s\n",
netdev->name);
@@ -832,11 +833,11 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
netdev->dev_addr[1], netdev->dev_addr[2], netdev->dev_addr[3],
netdev->dev_addr[4], netdev->dev_addr[5]);
-//sxg_init_bad:
+/*sxg_init_bad: */
ASSERT(status == FALSE);
-// sxg_free_adapter(adapter);
+/* sxg_free_adapter(adapter); */
- DBG_ERROR("sxg: %s EXIT status[%x] jiffies[%lx] cpu %d\n", __FUNCTION__,
+ DBG_ERROR("sxg: %s EXIT status[%x] jiffies[%lx] cpu %d\n", __func__,
status, jiffies, smp_processor_id());
return status;
@@ -848,7 +849,7 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
err_out_exit_sxg_probe:
- DBG_ERROR("%s EXIT jiffies[%lx] cpu %d\n", __FUNCTION__, jiffies,
+ DBG_ERROR("%s EXIT jiffies[%lx] cpu %d\n", __func__, jiffies,
smp_processor_id());
return -ENODEV;
@@ -874,12 +875,12 @@ static void sxg_disable_interrupt(p_adapter_t adapter)
{
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DisIntr",
adapter, adapter->InterruptsEnabled, 0, 0);
- // For now, RSS is disabled with line based interrupts
+ /* For now, RSS is disabled with line based interrupts */
ASSERT(adapter->RssEnabled == FALSE);
ASSERT(adapter->MsiEnabled == FALSE);
- //
- // Turn off interrupts by writing to the icr register.
- //
+ /* */
+ /* Turn off interrupts by writing to the icr register. */
+ /* */
WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_DISABLE), TRUE);
adapter->InterruptsEnabled = 0;
@@ -905,12 +906,12 @@ static void sxg_enable_interrupt(p_adapter_t adapter)
{
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "EnIntr",
adapter, adapter->InterruptsEnabled, 0, 0);
- // For now, RSS is disabled with line based interrupts
+ /* For now, RSS is disabled with line based interrupts */
ASSERT(adapter->RssEnabled == FALSE);
ASSERT(adapter->MsiEnabled == FALSE);
- //
- // Turn on interrupts by writing to the icr register.
- //
+ /* */
+ /* Turn on interrupts by writing to the icr register. */
+ /* */
WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_ENABLE), TRUE);
adapter->InterruptsEnabled = 1;
@@ -935,29 +936,29 @@ static irqreturn_t sxg_isr(int irq, void *dev_id)
{
p_net_device dev = (p_net_device) dev_id;
p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
-// u32 CpuMask = 0, i;
+/* u32 CpuMask = 0, i; */
adapter->Stats.NumInts++;
if (adapter->Isr[0] == 0) {
- // The SLIC driver used to experience a number of spurious interrupts
- // due to the delay associated with the masking of the interrupt
- // (we'd bounce back in here). If we see that again with Sahara,
- // add a READ_REG of the Icr register after the WRITE_REG below.
+ /* The SLIC driver used to experience a number of spurious interrupts */
+ /* due to the delay associated with the masking of the interrupt */
+ /* (we'd bounce back in here). If we see that again with Sahara, */
+ /* add a READ_REG of the Icr register after the WRITE_REG below. */
adapter->Stats.FalseInts++;
return IRQ_NONE;
}
- //
- // Move the Isr contents and clear the value in
- // shared memory, and mask interrupts
- //
+ /* */
+ /* Move the Isr contents and clear the value in */
+ /* shared memory, and mask interrupts */
+ /* */
adapter->IsrCopy[0] = adapter->Isr[0];
adapter->Isr[0] = 0;
WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_MASK), TRUE);
-// ASSERT(adapter->IsrDpcsPending == 0);
-#if XXXTODO // RSS Stuff
- // If RSS is enabled and the ISR specifies
- // SXG_ISR_EVENT, then schedule DPC's
- // based on event queues.
+/* ASSERT(adapter->IsrDpcsPending == 0); */
+#if XXXTODO /* RSS Stuff */
+ /* If RSS is enabled and the ISR specifies */
+ /* SXG_ISR_EVENT, then schedule DPC's */
+ /* based on event queues. */
if (adapter->RssEnabled && (adapter->IsrCopy[0] & SXG_ISR_EVENT)) {
for (i = 0;
i < adapter->RssSystemInfo->ProcessorInfo.RssCpuCount;
@@ -973,8 +974,8 @@ static irqreturn_t sxg_isr(int irq, void *dev_id)
}
}
}
- // Now, either schedule the CPUs specified by the CpuMask,
- // or queue default
+ /* Now, either schedule the CPUs specified by the CpuMask, */
+ /* or queue default */
if (CpuMask) {
*QueueDefault = FALSE;
} else {
@@ -983,9 +984,9 @@ static irqreturn_t sxg_isr(int irq, void *dev_id)
}
*TargetCpus = CpuMask;
#endif
- //
- // There are no DPCs in Linux, so call the handler now
- //
+ /* */
+ /* There are no DPCs in Linux, so call the handler now */
+ /* */
sxg_handle_interrupt(adapter);
return IRQ_HANDLED;
@@ -993,7 +994,7 @@ static irqreturn_t sxg_isr(int irq, void *dev_id)
static void sxg_handle_interrupt(p_adapter_t adapter)
{
-// unsigned char RssId = 0;
+/* unsigned char RssId = 0; */
u32 NewIsr;
if (adapter->Stats.RcvNoBuffer < 5) {
@@ -1002,32 +1003,32 @@ static void sxg_handle_interrupt(p_adapter_t adapter)
}
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "HndlIntr",
adapter, adapter->IsrCopy[0], 0, 0);
- // For now, RSS is disabled with line based interrupts
+ /* For now, RSS is disabled with line based interrupts */
ASSERT(adapter->RssEnabled == FALSE);
ASSERT(adapter->MsiEnabled == FALSE);
ASSERT(adapter->IsrCopy[0]);
-/////////////////////////////
+/*/////////////////////////// */
- // Always process the event queue.
+ /* Always process the event queue. */
sxg_process_event_queue(adapter,
(adapter->RssEnabled ? /*RssId */ 0 : 0));
-#if XXXTODO // RSS stuff
+#if XXXTODO /* RSS stuff */
if (--adapter->IsrDpcsPending) {
- // We're done.
+ /* We're done. */
ASSERT(adapter->RssEnabled);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DPCsPend",
adapter, 0, 0, 0);
return;
}
#endif
- //
- // Last (or only) DPC processes the ISR and clears the interrupt.
- //
+ /* */
+ /* Last (or only) DPC processes the ISR and clears the interrupt. */
+ /* */
NewIsr = sxg_process_isr(adapter, 0);
- //
- // Reenable interrupts
- //
+ /* */
+ /* Reenable interrupts */
+ /* */
adapter->IsrCopy[0] = 0;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "ClearIsr",
adapter, NewIsr, 0, 0);
@@ -1063,75 +1064,75 @@ static int sxg_process_isr(p_adapter_t adapter, u32 MessageId)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "ProcIsr",
adapter, Isr, 0, 0);
- // Error
+ /* Error */
if (Isr & SXG_ISR_ERR) {
if (Isr & SXG_ISR_PDQF) {
adapter->Stats.PdqFull++;
- DBG_ERROR("%s: SXG_ISR_ERR PDQF!!\n", __FUNCTION__);
+ DBG_ERROR("%s: SXG_ISR_ERR PDQF!!\n", __func__);
}
- // No host buffer
+ /* No host buffer */
if (Isr & SXG_ISR_RMISS) {
- // There is a bunch of code in the SLIC driver which
- // attempts to process more receive events per DPC
- // if we start to fall behind. We'll probably
- // need to do something similar here, but hold
- // off for now. I don't want to make the code more
- // complicated than strictly needed.
+ /* There is a bunch of code in the SLIC driver which */
+ /* attempts to process more receive events per DPC */
+ /* if we start to fall behind. We'll probably */
+ /* need to do something similar here, but hold */
+ /* off for now. I don't want to make the code more */
+ /* complicated than strictly needed. */
adapter->Stats.RcvNoBuffer++;
if (adapter->Stats.RcvNoBuffer < 5) {
DBG_ERROR("%s: SXG_ISR_ERR RMISS!!\n",
- __FUNCTION__);
+ __func__);
}
}
- // Card crash
+ /* Card crash */
if (Isr & SXG_ISR_DEAD) {
- // Set aside the crash info and set the adapter state to RESET
+ /* Set aside the crash info and set the adapter state to RESET */
adapter->CrashCpu =
(unsigned char)((Isr & SXG_ISR_CPU) >>
SXG_ISR_CPU_SHIFT);
adapter->CrashLocation = (ushort) (Isr & SXG_ISR_CRASH);
adapter->Dead = TRUE;
- DBG_ERROR("%s: ISR_DEAD %x, CPU: %d\n", __FUNCTION__,
+ DBG_ERROR("%s: ISR_DEAD %x, CPU: %d\n", __func__,
adapter->CrashLocation, adapter->CrashCpu);
}
- // Event ring full
+ /* Event ring full */
if (Isr & SXG_ISR_ERFULL) {
- // Same issue as RMISS, really. This means the
- // host is falling behind the card. Need to increase
- // event ring size, process more events per interrupt,
- // and/or reduce/remove interrupt aggregation.
+ /* Same issue as RMISS, really. This means the */
+ /* host is falling behind the card. Need to increase */
+ /* event ring size, process more events per interrupt, */
+ /* and/or reduce/remove interrupt aggregation. */
adapter->Stats.EventRingFull++;
DBG_ERROR("%s: SXG_ISR_ERR EVENT RING FULL!!\n",
- __FUNCTION__);
+ __func__);
}
- // Transmit drop - no DRAM buffers or XMT error
+ /* Transmit drop - no DRAM buffers or XMT error */
if (Isr & SXG_ISR_XDROP) {
adapter->Stats.XmtDrops++;
adapter->Stats.XmtErrors++;
- DBG_ERROR("%s: SXG_ISR_ERR XDROP!!\n", __FUNCTION__);
+ DBG_ERROR("%s: SXG_ISR_ERR XDROP!!\n", __func__);
}
}
- // Slowpath send completions
+ /* Slowpath send completions */
if (Isr & SXG_ISR_SPSEND) {
sxg_complete_slow_send(adapter);
}
- // Dump
+ /* Dump */
if (Isr & SXG_ISR_UPC) {
- ASSERT(adapter->DumpCmdRunning); // Maybe change when debug is added..
+ ASSERT(adapter->DumpCmdRunning); /* Maybe change when debug is added.. */
adapter->DumpCmdRunning = FALSE;
}
- // Link event
+ /* Link event */
if (Isr & SXG_ISR_LINK) {
sxg_link_event(adapter);
}
- // Debug - breakpoint hit
+ /* Debug - breakpoint hit */
if (Isr & SXG_ISR_BREAK) {
- // At the moment AGDB isn't written to support interactive
- // debug sessions. When it is, this interrupt will be used
- // to signal AGDB that it has hit a breakpoint. For now, ASSERT.
+ /* At the moment AGDB isn't written to support interactive */
+ /* debug sessions. When it is, this interrupt will be used */
+ /* to signal AGDB that it has hit a breakpoint. For now, ASSERT. */
ASSERT(0);
}
- // Heartbeat response
+ /* Heartbeat response */
if (Isr & SXG_ISR_PING) {
adapter->PingOutstanding = FALSE;
}
@@ -1171,39 +1172,39 @@ static u32 sxg_process_event_queue(p_adapter_t adapter, u32 RssId)
(adapter->State == SXG_STATE_PAUSING) ||
(adapter->State == SXG_STATE_PAUSED) ||
(adapter->State == SXG_STATE_HALTING));
- // We may still have unprocessed events on the queue if
- // the card crashed. Don't process them.
+ /* We may still have unprocessed events on the queue if */
+ /* the card crashed. Don't process them. */
if (adapter->Dead) {
return (0);
}
- // In theory there should only be a single processor that
- // accesses this queue, and only at interrupt-DPC time. So
- // we shouldn't need a lock for any of this.
+ /* In theory there should only be a single processor that */
+ /* accesses this queue, and only at interrupt-DPC time. So */
+ /* we shouldn't need a lock for any of this. */
while (Event->Status & EVENT_STATUS_VALID) {
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "Event",
Event, Event->Code, Event->Status,
adapter->NextEvent);
switch (Event->Code) {
case EVENT_CODE_BUFFERS:
- ASSERT(!(Event->CommandIndex & 0xFF00)); // SXG_RING_INFO Head & Tail == unsigned char
- //
+ ASSERT(!(Event->CommandIndex & 0xFF00)); /* SXG_RING_INFO Head & Tail == unsigned char */
+ /* */
sxg_complete_descriptor_blocks(adapter,
Event->CommandIndex);
- //
+ /* */
break;
case EVENT_CODE_SLOWRCV:
--adapter->RcvBuffersOnCard;
if ((skb = sxg_slow_receive(adapter, Event))) {
u32 rx_bytes;
#ifdef LINUX_HANDLES_RCV_INDICATION_LISTS
- // Add it to our indication list
+ /* Add it to our indication list */
SXG_ADD_RCV_PACKET(adapter, skb, prev_skb,
IndicationList, num_skbs);
- // In Linux, we just pass up each skb to the protocol above at this point,
- // there is no capability of an indication list.
+ /* In Linux, we just pass up each skb to the protocol above at this point, */
+ /* there is no capability of an indication list. */
#else
-// CHECK skb_pull(skb, INIC_RCVBUF_HEADSIZE);
- rx_bytes = Event->Length; // (rcvbuf->length & IRHDDR_FLEN_MSK);
+/* CHECK skb_pull(skb, INIC_RCVBUF_HEADSIZE); */
+ rx_bytes = Event->Length; /* (rcvbuf->length & IRHDDR_FLEN_MSK); */
skb_put(skb, rx_bytes);
adapter->stats.rx_packets++;
adapter->stats.rx_bytes += rx_bytes;
@@ -1218,43 +1219,43 @@ static u32 sxg_process_event_queue(p_adapter_t adapter, u32 RssId)
break;
default:
DBG_ERROR("%s: ERROR Invalid EventCode %d\n",
- __FUNCTION__, Event->Code);
-// ASSERT(0);
+ __func__, Event->Code);
+/* ASSERT(0); */
}
- // See if we need to restock card receive buffers.
- // There are two things to note here:
- // First - This test is not SMP safe. The
- // adapter->BuffersOnCard field is protected via atomic interlocked calls, but
- // we do not protect it with respect to these tests. The only way to do that
- // is with a lock, and I don't want to grab a lock every time we adjust the
- // BuffersOnCard count. Instead, we allow the buffer replenishment to be off
- // once in a while. The worst that can happen is the card is given one
- // more-or-less descriptor block than the arbitrary value we've chosen.
- // No big deal
- // In short DO NOT ADD A LOCK HERE, OR WHERE RcvBuffersOnCard is adjusted.
- // Second - We expect this test to rarely evaluate to true. We attempt to
- // refill descriptor blocks as they are returned to us
- // (sxg_complete_descriptor_blocks), so The only time this should evaluate
- // to true is when sxg_complete_descriptor_blocks failed to allocate
- // receive buffers.
+ /* See if we need to restock card receive buffers. */
+ /* There are two things to note here: */
+ /* First - This test is not SMP safe. The */
+ /* adapter->BuffersOnCard field is protected via atomic interlocked calls, but */
+ /* we do not protect it with respect to these tests. The only way to do that */
+ /* is with a lock, and I don't want to grab a lock every time we adjust the */
+ /* BuffersOnCard count. Instead, we allow the buffer replenishment to be off */
+ /* once in a while. The worst that can happen is the card is given one */
+ /* more-or-less descriptor block than the arbitrary value we've chosen. */
+ /* No big deal */
+ /* In short DO NOT ADD A LOCK HERE, OR WHERE RcvBuffersOnCard is adjusted. */
+ /* Second - We expect this test to rarely evaluate to true. We attempt to */
+ /* refill descriptor blocks as they are returned to us */
+ /* (sxg_complete_descriptor_blocks), so The only time this should evaluate */
+ /* to true is when sxg_complete_descriptor_blocks failed to allocate */
+ /* receive buffers. */
if (adapter->RcvBuffersOnCard < SXG_RCV_DATA_BUFFERS) {
sxg_stock_rcv_buffers(adapter);
}
- // It's more efficient to just set this to zero.
- // But clearing the top bit saves potential debug info...
+ /* It's more efficient to just set this to zero. */
+ /* But clearing the top bit saves potential debug info... */
Event->Status &= ~EVENT_STATUS_VALID;
- // Advanct to the next event
+ /* Advanct to the next event */
SXG_ADVANCE_INDEX(adapter->NextEvent[RssId], EVENT_RING_SIZE);
Event = &EventRing->Ring[adapter->NextEvent[RssId]];
EventsProcessed++;
if (EventsProcessed == EVENT_RING_BATCH) {
- // Release a batch of events back to the card
+ /* Release a batch of events back to the card */
WRITE_REG(adapter->UcodeRegs[RssId].EventRelease,
EVENT_RING_BATCH, FALSE);
EventsProcessed = 0;
- // If we've processed our batch limit, break out of the
- // loop and return SXG_ISR_EVENT to arrange for us to
- // be called again
+ /* If we've processed our batch limit, break out of the */
+ /* loop and return SXG_ISR_EVENT to arrange for us to */
+ /* be called again */
if (Batches++ == EVENT_BATCH_LIMIT) {
SXG_TRACE(TRACE_SXG, SxgTraceBuffer,
TRACE_NOISY, "EvtLimit", Batches,
@@ -1265,14 +1266,14 @@ static u32 sxg_process_event_queue(p_adapter_t adapter, u32 RssId)
}
}
#ifdef LINUX_HANDLES_RCV_INDICATION_LISTS
- //
- // Indicate any received dumb-nic frames
- //
+ /* */
+ /* Indicate any received dumb-nic frames */
+ /* */
SXG_INDICATE_PACKETS(adapter, IndicationList, num_skbs);
#endif
- //
- // Release events back to the card.
- //
+ /* */
+ /* Release events back to the card. */
+ /* */
if (EventsProcessed) {
WRITE_REG(adapter->UcodeRegs[RssId].EventRelease,
EventsProcessed, FALSE);
@@ -1299,43 +1300,43 @@ static void sxg_complete_slow_send(p_adapter_t adapter)
u32 *ContextType;
PSXG_CMD XmtCmd;
- // NOTE - This lock is dropped and regrabbed in this loop.
- // This means two different processors can both be running
- // through this loop. Be *very* careful.
+ /* NOTE - This lock is dropped and regrabbed in this loop. */
+ /* This means two different processors can both be running */
+ /* through this loop. Be *very* careful. */
spin_lock(&adapter->XmtZeroLock);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnds",
adapter, XmtRingInfo->Head, XmtRingInfo->Tail, 0);
while (XmtRingInfo->Tail != *adapter->XmtRingZeroIndex) {
- // Locate the current Cmd (ring descriptor entry), and
- // associated SGL, and advance the tail
+ /* Locate the current Cmd (ring descriptor entry), and */
+ /* associated SGL, and advance the tail */
SXG_RETURN_CMD(XmtRing, XmtRingInfo, XmtCmd, ContextType);
ASSERT(ContextType);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnd",
XmtRingInfo->Head, XmtRingInfo->Tail, XmtCmd, 0);
- // Clear the SGL field.
+ /* Clear the SGL field. */
XmtCmd->Sgl = 0;
switch (*ContextType) {
case SXG_SGL_DUMB:
{
struct sk_buff *skb;
- // Dumb-nic send. Command context is the dumb-nic SGL
+ /* Dumb-nic send. Command context is the dumb-nic SGL */
skb = (struct sk_buff *)ContextType;
- // Complete the send
+ /* Complete the send */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer,
TRACE_IMPORTANT, "DmSndCmp", skb, 0,
0, 0);
ASSERT(adapter->Stats.XmtQLen);
- adapter->Stats.XmtQLen--; // within XmtZeroLock
+ adapter->Stats.XmtQLen--; /* within XmtZeroLock */
adapter->Stats.XmtOk++;
- // Now drop the lock and complete the send back to
- // Microsoft. We need to drop the lock because
- // Microsoft can come back with a chimney send, which
- // results in a double trip in SxgTcpOuput
+ /* Now drop the lock and complete the send back to */
+ /* Microsoft. We need to drop the lock because */
+ /* Microsoft can come back with a chimney send, which */
+ /* results in a double trip in SxgTcpOuput */
spin_unlock(&adapter->XmtZeroLock);
SXG_COMPLETE_DUMB_SEND(adapter, skb);
- // and reacquire..
+ /* and reacquire.. */
spin_lock(&adapter->XmtZeroLock);
}
break;
@@ -1371,7 +1372,7 @@ static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "SlowRcv", Event,
RcvDataBufferHdr, RcvDataBufferHdr->State,
RcvDataBufferHdr->VirtualAddress);
- // Drop rcv frames in non-running state
+ /* Drop rcv frames in non-running state */
switch (adapter->State) {
case SXG_STATE_RUNNING:
break;
@@ -1384,12 +1385,12 @@ static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event)
goto drop;
}
- // Change buffer state to UPSTREAM
+ /* Change buffer state to UPSTREAM */
RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM;
if (Event->Status & EVENT_STATUS_RCVERR) {
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvError",
Event, Event->Status, Event->HostHandle, 0);
- // XXXTODO - Remove this print later
+ /* XXXTODO - Remove this print later */
DBG_ERROR("SXG: Receive error %x\n", *(u32 *)
SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr));
sxg_process_rcv_error(adapter, *(u32 *)
@@ -1397,8 +1398,8 @@ static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event)
(RcvDataBufferHdr));
goto drop;
}
-#if XXXTODO // VLAN stuff
- // If there's a VLAN tag, extract it and validate it
+#if XXXTODO /* VLAN stuff */
+ /* If there's a VLAN tag, extract it and validate it */
if (((p_ether_header) (SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)))->
EtherType == ETHERTYPE_VLAN) {
if (SxgExtractVlanHeader(adapter, RcvDataBufferHdr, Event) !=
@@ -1411,9 +1412,9 @@ static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event)
}
}
#endif
- //
- // Dumb-nic frame. See if it passes our mac filter and update stats
- //
+ /* */
+ /* Dumb-nic frame. See if it passes our mac filter and update stats */
+ /* */
if (!sxg_mac_filter(adapter, (p_ether_header)
SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
Event->Length)) {
@@ -1427,9 +1428,9 @@ static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "DumbRcv",
RcvDataBufferHdr, Packet, Event->Length, 0);
- //
- // Lastly adjust the receive packet length.
- //
+ /* */
+ /* Lastly adjust the receive packet length. */
+ /* */
SXG_ADJUST_RCV_PACKET(Packet, RcvDataBufferHdr, Event);
return (Packet);
@@ -1541,7 +1542,7 @@ static bool sxg_mac_filter(p_adapter_t adapter, p_ether_header EtherHdr,
if (SXG_MULTICAST_PACKET(EtherHdr)) {
if (SXG_BROADCAST_PACKET(EtherHdr)) {
- // broadcast
+ /* broadcast */
if (adapter->MacFilter & MAC_BCAST) {
adapter->Stats.DumbRcvBcastPkts++;
adapter->Stats.DumbRcvBcastBytes += length;
@@ -1550,7 +1551,7 @@ static bool sxg_mac_filter(p_adapter_t adapter, p_ether_header EtherHdr,
return (TRUE);
}
} else {
- // multicast
+ /* multicast */
if (adapter->MacFilter & MAC_ALLMCAST) {
adapter->Stats.DumbRcvMcastPkts++;
adapter->Stats.DumbRcvMcastBytes += length;
@@ -1580,9 +1581,9 @@ static bool sxg_mac_filter(p_adapter_t adapter, p_ether_header EtherHdr,
}
}
} else if (adapter->MacFilter & MAC_DIRECTED) {
- // Not broadcast or multicast. Must be directed at us or
- // the card is in promiscuous mode. Either way, consider it
- // ours if MAC_DIRECTED is set
+ /* Not broadcast or multicast. Must be directed at us or */
+ /* the card is in promiscuous mode. Either way, consider it */
+ /* ours if MAC_DIRECTED is set */
adapter->Stats.DumbRcvUcastPkts++;
adapter->Stats.DumbRcvUcastBytes += length;
adapter->Stats.DumbRcvPkts++;
@@ -1590,7 +1591,7 @@ static bool sxg_mac_filter(p_adapter_t adapter, p_ether_header EtherHdr,
return (TRUE);
}
if (adapter->MacFilter & MAC_PROMISC) {
- // Whatever it is, keep it.
+ /* Whatever it is, keep it. */
adapter->Stats.DumbRcvPkts++;
adapter->Stats.DumbRcvBytes += length;
return (TRUE);
@@ -1606,7 +1607,7 @@ static int sxg_register_interrupt(p_adapter_t adapter)
DBG_ERROR
("sxg: %s AllocAdaptRsrcs adapter[%p] dev->irq[%x] %x\n",
- __FUNCTION__, adapter, adapter->netdev->irq, NR_IRQS);
+ __func__, adapter, adapter->netdev->irq, NR_IRQS);
spin_unlock_irqrestore(&sxg_global.driver_lock,
sxg_global.flags);
@@ -1625,18 +1626,18 @@ static int sxg_register_interrupt(p_adapter_t adapter)
}
adapter->intrregistered = 1;
adapter->IntRegistered = TRUE;
- // Disable RSS with line-based interrupts
+ /* Disable RSS with line-based interrupts */
adapter->MsiEnabled = FALSE;
adapter->RssEnabled = FALSE;
DBG_ERROR("sxg: %s AllocAdaptRsrcs adapter[%p] dev->irq[%x]\n",
- __FUNCTION__, adapter, adapter->netdev->irq);
+ __func__, adapter, adapter->netdev->irq);
}
return (STATUS_SUCCESS);
}
static void sxg_deregister_interrupt(p_adapter_t adapter)
{
- DBG_ERROR("sxg: %s ENTER adapter[%p]\n", __FUNCTION__, adapter);
+ DBG_ERROR("sxg: %s ENTER adapter[%p]\n", __func__, adapter);
#if XXXTODO
slic_init_cleanup(adapter);
#endif
@@ -1651,7 +1652,7 @@ static void sxg_deregister_interrupt(p_adapter_t adapter)
adapter->rcv_broadcasts = 0;
adapter->rcv_multicasts = 0;
adapter->rcv_unicasts = 0;
- DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s EXIT\n", __func__);
}
/*
@@ -1666,7 +1667,7 @@ static int sxg_if_init(p_adapter_t adapter)
int status = 0;
DBG_ERROR("sxg: %s (%s) ENTER states[%d:%d:%d] flags[%x]\n",
- __FUNCTION__, adapter->netdev->name,
+ __func__, adapter->netdev->name,
adapter->queues_initialized, adapter->state,
adapter->linkstate, dev->flags);
@@ -1680,7 +1681,7 @@ static int sxg_if_init(p_adapter_t adapter)
adapter->devflags_prev = dev->flags;
adapter->macopts = MAC_DIRECTED;
if (dev->flags) {
- DBG_ERROR("sxg: %s (%s) Set MAC options: ", __FUNCTION__,
+ DBG_ERROR("sxg: %s (%s) Set MAC options: ", __func__,
adapter->netdev->name);
if (dev->flags & IFF_BROADCAST) {
adapter->macopts |= MAC_BCAST;
@@ -1713,7 +1714,7 @@ static int sxg_if_init(p_adapter_t adapter)
/*
* clear any pending events, then enable interrupts
*/
- DBG_ERROR("sxg: %s ENABLE interrupts(slic)\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s ENABLE interrupts(slic)\n", __func__);
return (STATUS_SUCCESS);
}
@@ -1724,11 +1725,11 @@ static int sxg_entry_open(p_net_device dev)
int status;
ASSERT(adapter);
- DBG_ERROR("sxg: %s adapter->activated[%d]\n", __FUNCTION__,
+ DBG_ERROR("sxg: %s adapter->activated[%d]\n", __func__,
adapter->activated);
DBG_ERROR
("sxg: %s (%s): [jiffies[%lx] cpu %d] dev[%p] adapt[%p] port[%d]\n",
- __FUNCTION__, adapter->netdev->name, jiffies, smp_processor_id(),
+ __func__, adapter->netdev->name, jiffies, smp_processor_id(),
adapter->netdev, adapter, adapter->port);
netif_stop_queue(adapter->netdev);
@@ -1738,16 +1739,16 @@ static int sxg_entry_open(p_net_device dev)
sxg_global.num_sxg_ports_active++;
adapter->activated = 1;
}
- // Initialize the adapter
- DBG_ERROR("sxg: %s ENTER sxg_initialize_adapter\n", __FUNCTION__);
+ /* Initialize the adapter */
+ DBG_ERROR("sxg: %s ENTER sxg_initialize_adapter\n", __func__);
status = sxg_initialize_adapter(adapter);
DBG_ERROR("sxg: %s EXIT sxg_initialize_adapter status[%x]\n",
- __FUNCTION__, status);
+ __func__, status);
if (status == STATUS_SUCCESS) {
- DBG_ERROR("sxg: %s ENTER sxg_if_init\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s ENTER sxg_if_init\n", __func__);
status = sxg_if_init(adapter);
- DBG_ERROR("sxg: %s EXIT sxg_if_init status[%x]\n", __FUNCTION__,
+ DBG_ERROR("sxg: %s EXIT sxg_if_init status[%x]\n", __func__,
status);
}
@@ -1760,12 +1761,12 @@ static int sxg_entry_open(p_net_device dev)
sxg_global.flags);
return (status);
}
- DBG_ERROR("sxg: %s ENABLE ALL INTERRUPTS\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s ENABLE ALL INTERRUPTS\n", __func__);
- // Enable interrupts
+ /* Enable interrupts */
SXG_ENABLE_ALL_INTERRUPTS(adapter);
- DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s EXIT\n", __func__);
spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags);
return STATUS_SUCCESS;
@@ -1779,27 +1780,27 @@ static void __devexit sxg_entry_remove(struct pci_dev *pcidev)
p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
ASSERT(adapter);
- DBG_ERROR("sxg: %s ENTER dev[%p] adapter[%p]\n", __FUNCTION__, dev,
+ DBG_ERROR("sxg: %s ENTER dev[%p] adapter[%p]\n", __func__, dev,
adapter);
sxg_deregister_interrupt(adapter);
sxg_unmap_mmio_space(adapter);
- DBG_ERROR("sxg: %s unregister_netdev\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s unregister_netdev\n", __func__);
unregister_netdev(dev);
mmio_start = pci_resource_start(pcidev, 0);
mmio_len = pci_resource_len(pcidev, 0);
- DBG_ERROR("sxg: %s rel_region(0) start[%x] len[%x]\n", __FUNCTION__,
+ DBG_ERROR("sxg: %s rel_region(0) start[%x] len[%x]\n", __func__,
mmio_start, mmio_len);
release_mem_region(mmio_start, mmio_len);
- DBG_ERROR("sxg: %s iounmap dev->base_addr[%x]\n", __FUNCTION__,
+ DBG_ERROR("sxg: %s iounmap dev->base_addr[%x]\n", __func__,
(unsigned int)dev->base_addr);
iounmap((char *)dev->base_addr);
- DBG_ERROR("sxg: %s deallocate device\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s deallocate device\n", __func__);
kfree(dev);
- DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s EXIT\n", __func__);
}
static int sxg_entry_halt(p_net_device dev)
@@ -1807,17 +1808,17 @@ static int sxg_entry_halt(p_net_device dev)
p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
spin_lock_irqsave(&sxg_global.driver_lock, sxg_global.flags);
- DBG_ERROR("sxg: %s (%s) ENTER\n", __FUNCTION__, dev->name);
+ DBG_ERROR("sxg: %s (%s) ENTER\n", __func__, dev->name);
netif_stop_queue(adapter->netdev);
adapter->state = ADAPT_DOWN;
adapter->linkstate = LINK_DOWN;
adapter->devflags_prev = 0;
DBG_ERROR("sxg: %s (%s) set adapter[%p] state to ADAPT_DOWN(%d)\n",
- __FUNCTION__, dev->name, adapter, adapter->state);
+ __func__, dev->name, adapter, adapter->state);
- DBG_ERROR("sxg: %s (%s) EXIT\n", __FUNCTION__, dev->name);
- DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__);
+ DBG_ERROR("sxg: %s (%s) EXIT\n", __func__, dev->name);
+ DBG_ERROR("sxg: %s EXIT\n", __func__);
spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags);
return (STATUS_SUCCESS);
}
@@ -1825,11 +1826,11 @@ static int sxg_entry_halt(p_net_device dev)
static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd)
{
ASSERT(rq);
-// DBG_ERROR("sxg: %s cmd[%x] rq[%p] dev[%p]\n", __FUNCTION__, cmd, rq, dev);
+/* DBG_ERROR("sxg: %s cmd[%x] rq[%p] dev[%p]\n", __func__, cmd, rq, dev); */
switch (cmd) {
case SIOCSLICSETINTAGG:
{
-// p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
+/* p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); */
u32 data[7];
u32 intagg;
@@ -1841,12 +1842,12 @@ static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd)
intagg = data[0];
printk(KERN_EMERG
"%s: set interrupt aggregation to %d\n",
- __FUNCTION__, intagg);
+ __func__, intagg);
return 0;
}
default:
-// DBG_ERROR("sxg: %s UNSUPPORTED[%x]\n", __FUNCTION__, cmd);
+/* DBG_ERROR("sxg: %s UNSUPPORTED[%x]\n", __func__, cmd); */
return -EOPNOTSUPP;
}
return 0;
@@ -1870,15 +1871,15 @@ static int sxg_send_packets(struct sk_buff *skb, p_net_device dev)
p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
u32 status = STATUS_SUCCESS;
- DBG_ERROR("sxg: %s ENTER sxg_send_packets skb[%p]\n", __FUNCTION__,
+ DBG_ERROR("sxg: %s ENTER sxg_send_packets skb[%p]\n", __func__,
skb);
- // Check the adapter state
+ /* Check the adapter state */
switch (adapter->State) {
case SXG_STATE_INITIALIZING:
case SXG_STATE_HALTED:
case SXG_STATE_SHUTDOWN:
- ASSERT(0); // unexpected
- // fall through
+ ASSERT(0); /* unexpected */
+ /* fall through */
case SXG_STATE_RESETTING:
case SXG_STATE_SLEEP:
case SXG_STATE_BOOTDIAG:
@@ -1898,23 +1899,23 @@ static int sxg_send_packets(struct sk_buff *skb, p_net_device dev)
if (status != STATUS_SUCCESS) {
goto xmit_fail;
}
- // send a packet
+ /* send a packet */
status = sxg_transmit_packet(adapter, skb);
if (status == STATUS_SUCCESS) {
goto xmit_done;
}
xmit_fail:
- // reject & complete all the packets if they cant be sent
+ /* reject & complete all the packets if they cant be sent */
if (status != STATUS_SUCCESS) {
#if XXXTODO
-// sxg_send_packets_fail(adapter, skb, status);
+/* sxg_send_packets_fail(adapter, skb, status); */
#else
SXG_DROP_DUMB_SEND(adapter, skb);
adapter->stats.tx_dropped++;
#endif
}
- DBG_ERROR("sxg: %s EXIT sxg_send_packets status[%x]\n", __FUNCTION__,
+ DBG_ERROR("sxg: %s EXIT sxg_send_packets status[%x]\n", __func__,
status);
xmit_done:
@@ -1940,12 +1941,12 @@ static int sxg_transmit_packet(p_adapter_t adapter, struct sk_buff *skb)
void *SglBuffer;
u32 SglBufferLength;
- // The vast majority of work is done in the shared
- // sxg_dumb_sgl routine.
+ /* The vast majority of work is done in the shared */
+ /* sxg_dumb_sgl routine. */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSend",
adapter, skb, 0, 0);
- // Allocate a SGL buffer
+ /* Allocate a SGL buffer */
SXG_GET_SGL_BUFFER(adapter, SxgSgl);
if (!SxgSgl) {
adapter->Stats.NoSglBuf++;
@@ -1963,9 +1964,9 @@ static int sxg_transmit_packet(p_adapter_t adapter, struct sk_buff *skb)
SxgSgl->DumbPacket = skb;
pSgl = NULL;
- // Call the common sxg_dumb_sgl routine to complete the send.
+ /* Call the common sxg_dumb_sgl routine to complete the send. */
sxg_dumb_sgl(pSgl, SxgSgl);
- // Return success sxg_dumb_sgl (or something later) will complete it.
+ /* Return success sxg_dumb_sgl (or something later) will complete it. */
return (STATUS_SUCCESS);
}
@@ -1983,39 +1984,39 @@ static void sxg_dumb_sgl(PSCATTER_GATHER_LIST pSgl, PSXG_SCATTER_GATHER SxgSgl)
{
p_adapter_t adapter = SxgSgl->adapter;
struct sk_buff *skb = SxgSgl->DumbPacket;
- // For now, all dumb-nic sends go on RSS queue zero
+ /* For now, all dumb-nic sends go on RSS queue zero */
PSXG_XMT_RING XmtRing = &adapter->XmtRings[0];
PSXG_RING_INFO XmtRingInfo = &adapter->XmtRingZeroInfo;
PSXG_CMD XmtCmd = NULL;
-// u32 Index = 0;
+/* u32 Index = 0; */
u32 DataLength = skb->len;
-// unsigned int BufLen;
-// u32 SglOffset;
+/* unsigned int BufLen; */
+/* u32 SglOffset; */
u64 phys_addr;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSgl",
pSgl, SxgSgl, 0, 0);
- // Set aside a pointer to the sgl
+ /* Set aside a pointer to the sgl */
SxgSgl->pSgl = pSgl;
- // Sanity check that our SGL format is as we expect.
+ /* Sanity check that our SGL format is as we expect. */
ASSERT(sizeof(SXG_X64_SGE) == sizeof(SCATTER_GATHER_ELEMENT));
- // Shouldn't be a vlan tag on this frame
+ /* Shouldn't be a vlan tag on this frame */
ASSERT(SxgSgl->VlanTag.VlanTci == 0);
ASSERT(SxgSgl->VlanTag.VlanTpid == 0);
- // From here below we work with the SGL placed in our
- // buffer.
+ /* From here below we work with the SGL placed in our */
+ /* buffer. */
SxgSgl->Sgl.NumberOfElements = 1;
- // Grab the spinlock and acquire a command
+ /* Grab the spinlock and acquire a command */
spin_lock(&adapter->XmtZeroLock);
SXG_GET_CMD(XmtRing, XmtRingInfo, XmtCmd, SxgSgl);
if (XmtCmd == NULL) {
- // Call sxg_complete_slow_send to see if we can
- // free up any XmtRingZero entries and then try again
+ /* Call sxg_complete_slow_send to see if we can */
+ /* free up any XmtRingZero entries and then try again */
spin_unlock(&adapter->XmtZeroLock);
sxg_complete_slow_send(adapter);
spin_lock(&adapter->XmtZeroLock);
@@ -2027,10 +2028,10 @@ static void sxg_dumb_sgl(PSCATTER_GATHER_LIST pSgl, PSXG_SCATTER_GATHER SxgSgl)
}
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbCmd",
XmtCmd, XmtRingInfo->Head, XmtRingInfo->Tail, 0);
- // Update stats
+ /* Update stats */
adapter->Stats.DumbXmtPkts++;
adapter->Stats.DumbXmtBytes += DataLength;
-#if XXXTODO // Stats stuff
+#if XXXTODO /* Stats stuff */
if (SXG_MULTICAST_PACKET(EtherHdr)) {
if (SXG_BROADCAST_PACKET(EtherHdr)) {
adapter->Stats.DumbXmtBcastPkts++;
@@ -2044,8 +2045,8 @@ static void sxg_dumb_sgl(PSCATTER_GATHER_LIST pSgl, PSXG_SCATTER_GATHER SxgSgl)
adapter->Stats.DumbXmtUcastBytes += DataLength;
}
#endif
- // Fill in the command
- // Copy out the first SGE to the command and adjust for offset
+ /* Fill in the command */
+ /* Copy out the first SGE to the command and adjust for offset */
phys_addr =
pci_map_single(adapter->pcidev, skb->data, skb->len,
PCI_DMA_TODEVICE);
@@ -2053,54 +2054,54 @@ static void sxg_dumb_sgl(PSCATTER_GATHER_LIST pSgl, PSXG_SCATTER_GATHER SxgSgl)
XmtCmd->Buffer.FirstSgeAddress = XmtCmd->Buffer.FirstSgeAddress << 32;
XmtCmd->Buffer.FirstSgeAddress =
XmtCmd->Buffer.FirstSgeAddress | SXG_GET_ADDR_LOW(phys_addr);
-// XmtCmd->Buffer.FirstSgeAddress = SxgSgl->Sgl.Elements[Index].Address;
-// XmtCmd->Buffer.FirstSgeAddress.LowPart += MdlOffset;
+/* XmtCmd->Buffer.FirstSgeAddress = SxgSgl->Sgl.Elements[Index].Address; */
+/* XmtCmd->Buffer.FirstSgeAddress.LowPart += MdlOffset; */
XmtCmd->Buffer.FirstSgeLength = DataLength;
- // Set a pointer to the remaining SGL entries
-// XmtCmd->Sgl = SxgSgl->PhysicalAddress;
- // Advance the physical address of the SxgSgl structure to
- // the second SGE
-// SglOffset = (u32)((u32 *)(&SxgSgl->Sgl.Elements[Index+1]) -
-// (u32 *)SxgSgl);
-// XmtCmd->Sgl.LowPart += SglOffset;
+ /* Set a pointer to the remaining SGL entries */
+/* XmtCmd->Sgl = SxgSgl->PhysicalAddress; */
+ /* Advance the physical address of the SxgSgl structure to */
+ /* the second SGE */
+/* SglOffset = (u32)((u32 *)(&SxgSgl->Sgl.Elements[Index+1]) - */
+/* (u32 *)SxgSgl); */
+/* XmtCmd->Sgl.LowPart += SglOffset; */
XmtCmd->Buffer.SgeOffset = 0;
- // Note - TotalLength might be overwritten with MSS below..
+ /* Note - TotalLength might be overwritten with MSS below.. */
XmtCmd->Buffer.TotalLength = DataLength;
- XmtCmd->SgEntries = 1; //(ushort)(SxgSgl->Sgl.NumberOfElements - Index);
+ XmtCmd->SgEntries = 1; /*(ushort)(SxgSgl->Sgl.NumberOfElements - Index); */
XmtCmd->Flags = 0;
- //
- // Advance transmit cmd descripter by 1.
- // NOTE - See comments in SxgTcpOutput where we write
- // to the XmtCmd register regarding CPU ID values and/or
- // multiple commands.
- //
- //
+ /* */
+ /* Advance transmit cmd descripter by 1. */
+ /* NOTE - See comments in SxgTcpOutput where we write */
+ /* to the XmtCmd register regarding CPU ID values and/or */
+ /* multiple commands. */
+ /* */
+ /* */
WRITE_REG(adapter->UcodeRegs[0].XmtCmd, 1, TRUE);
- //
- //
- adapter->Stats.XmtQLen++; // Stats within lock
+ /* */
+ /* */
+ adapter->Stats.XmtQLen++; /* Stats within lock */
spin_unlock(&adapter->XmtZeroLock);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDumSgl2",
XmtCmd, pSgl, SxgSgl, 0);
return;
abortcmd:
- // NOTE - Only jump to this label AFTER grabbing the
- // XmtZeroLock, and DO NOT DROP IT between the
- // command allocation and the following abort.
+ /* NOTE - Only jump to this label AFTER grabbing the */
+ /* XmtZeroLock, and DO NOT DROP IT between the */
+ /* command allocation and the following abort. */
if (XmtCmd) {
SXG_ABORT_CMD(XmtRingInfo);
}
spin_unlock(&adapter->XmtZeroLock);
-// failsgl:
- // Jump to this label if failure occurs before the
- // XmtZeroLock is grabbed
+/* failsgl: */
+ /* Jump to this label if failure occurs before the */
+ /* XmtZeroLock is grabbed */
adapter->Stats.XmtErrors++;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "DumSGFal",
pSgl, SxgSgl, XmtRingInfo->Head, XmtRingInfo->Tail);
- SXG_COMPLETE_DUMB_SEND(adapter, SxgSgl->DumbPacket); // SxgSgl->DumbPacket is the skb
+ SXG_COMPLETE_DUMB_SEND(adapter, SxgSgl->DumbPacket); /* SxgSgl->DumbPacket is the skb */
}
/***************************************************************
@@ -2127,122 +2128,122 @@ static int sxg_initialize_link(p_adapter_t adapter)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "InitLink",
adapter, 0, 0, 0);
- // Reset PHY and XGXS module
+ /* Reset PHY and XGXS module */
WRITE_REG(HwRegs->LinkStatus, LS_SERDES_POWER_DOWN, TRUE);
- // Reset transmit configuration register
+ /* Reset transmit configuration register */
WRITE_REG(HwRegs->XmtConfig, XMT_CONFIG_RESET, TRUE);
- // Reset receive configuration register
+ /* Reset receive configuration register */
WRITE_REG(HwRegs->RcvConfig, RCV_CONFIG_RESET, TRUE);
- // Reset all MAC modules
+ /* Reset all MAC modules */
WRITE_REG(HwRegs->MacConfig0, AXGMAC_CFG0_SUB_RESET, TRUE);
- // Link address 0
- // XXXTODO - This assumes the MAC address (0a:0b:0c:0d:0e:0f)
- // is stored with the first nibble (0a) in the byte 0
- // of the Mac address. Possibly reverse?
+ /* Link address 0 */
+ /* XXXTODO - This assumes the MAC address (0a:0b:0c:0d:0e:0f) */
+ /* is stored with the first nibble (0a) in the byte 0 */
+ /* of the Mac address. Possibly reverse? */
Value = *(u32 *) adapter->MacAddr;
WRITE_REG(HwRegs->LinkAddress0Low, Value, TRUE);
- // also write the MAC address to the MAC. Endian is reversed.
+ /* also write the MAC address to the MAC. Endian is reversed. */
WRITE_REG(HwRegs->MacAddressLow, ntohl(Value), TRUE);
Value = (*(u16 *) & adapter->MacAddr[4] & 0x0000FFFF);
WRITE_REG(HwRegs->LinkAddress0High, Value | LINK_ADDRESS_ENABLE, TRUE);
- // endian swap for the MAC (put high bytes in bits [31:16], swapped)
+ /* endian swap for the MAC (put high bytes in bits [31:16], swapped) */
Value = ntohl(Value);
WRITE_REG(HwRegs->MacAddressHigh, Value, TRUE);
- // Link address 1
+ /* Link address 1 */
WRITE_REG(HwRegs->LinkAddress1Low, 0, TRUE);
WRITE_REG(HwRegs->LinkAddress1High, 0, TRUE);
- // Link address 2
+ /* Link address 2 */
WRITE_REG(HwRegs->LinkAddress2Low, 0, TRUE);
WRITE_REG(HwRegs->LinkAddress2High, 0, TRUE);
- // Link address 3
+ /* Link address 3 */
WRITE_REG(HwRegs->LinkAddress3Low, 0, TRUE);
WRITE_REG(HwRegs->LinkAddress3High, 0, TRUE);
- // Enable MAC modules
+ /* Enable MAC modules */
WRITE_REG(HwRegs->MacConfig0, 0, TRUE);
- // Configure MAC
- WRITE_REG(HwRegs->MacConfig1, (AXGMAC_CFG1_XMT_PAUSE | // Allow sending of pause
- AXGMAC_CFG1_XMT_EN | // Enable XMT
- AXGMAC_CFG1_RCV_PAUSE | // Enable detection of pause
- AXGMAC_CFG1_RCV_EN | // Enable receive
- AXGMAC_CFG1_SHORT_ASSERT | // short frame detection
- AXGMAC_CFG1_CHECK_LEN | // Verify frame length
- AXGMAC_CFG1_GEN_FCS | // Generate FCS
- AXGMAC_CFG1_PAD_64), // Pad frames to 64 bytes
+ /* Configure MAC */
+ WRITE_REG(HwRegs->MacConfig1, (AXGMAC_CFG1_XMT_PAUSE | /* Allow sending of pause */
+ AXGMAC_CFG1_XMT_EN | /* Enable XMT */
+ AXGMAC_CFG1_RCV_PAUSE | /* Enable detection of pause */
+ AXGMAC_CFG1_RCV_EN | /* Enable receive */
+ AXGMAC_CFG1_SHORT_ASSERT | /* short frame detection */
+ AXGMAC_CFG1_CHECK_LEN | /* Verify frame length */
+ AXGMAC_CFG1_GEN_FCS | /* Generate FCS */
+ AXGMAC_CFG1_PAD_64), /* Pad frames to 64 bytes */
TRUE);
- // Set AXGMAC max frame length if jumbo. Not needed for standard MTU
+ /* Set AXGMAC max frame length if jumbo. Not needed for standard MTU */
if (adapter->JumboEnabled) {
WRITE_REG(HwRegs->MacMaxFrameLen, AXGMAC_MAXFRAME_JUMBO, TRUE);
}
- // AMIIM Configuration Register -
- // The value placed in the AXGMAC_AMIIM_CFG_HALF_CLOCK portion
- // (bottom bits) of this register is used to determine the
- // MDC frequency as specified in the A-XGMAC Design Document.
- // This value must not be zero. The following value (62 or 0x3E)
- // is based on our MAC transmit clock frequency (MTCLK) of 312.5 MHz.
- // Given a maximum MDIO clock frequency of 2.5 MHz (see the PHY spec),
- // we get: 312.5/(2*(X+1)) < 2.5 ==> X = 62.
- // This value happens to be the default value for this register,
- // so we really don't have to do this.
+ /* AMIIM Configuration Register - */
+ /* The value placed in the AXGMAC_AMIIM_CFG_HALF_CLOCK portion */
+ /* (bottom bits) of this register is used to determine the */
+ /* MDC frequency as specified in the A-XGMAC Design Document. */
+ /* This value must not be zero. The following value (62 or 0x3E) */
+ /* is based on our MAC transmit clock frequency (MTCLK) of 312.5 MHz. */
+ /* Given a maximum MDIO clock frequency of 2.5 MHz (see the PHY spec), */
+ /* we get: 312.5/(2*(X+1)) < 2.5 ==> X = 62. */
+ /* This value happens to be the default value for this register, */
+ /* so we really don't have to do this. */
WRITE_REG(HwRegs->MacAmiimConfig, 0x0000003E, TRUE);
- // Power up and enable PHY and XAUI/XGXS/Serdes logic
+ /* Power up and enable PHY and XAUI/XGXS/Serdes logic */
WRITE_REG(HwRegs->LinkStatus,
(LS_PHY_CLR_RESET |
LS_XGXS_ENABLE |
LS_XGXS_CTL | LS_PHY_CLK_EN | LS_ATTN_ALARM), TRUE);
DBG_ERROR("After Power Up and enable PHY in sxg_initialize_link\n");
- // Per information given by Aeluros, wait 100 ms after removing reset.
- // It's not enough to wait for the self-clearing reset bit in reg 0 to clear.
+ /* Per information given by Aeluros, wait 100 ms after removing reset. */
+ /* It's not enough to wait for the self-clearing reset bit in reg 0 to clear. */
mdelay(100);
- // Verify the PHY has come up by checking that the Reset bit has cleared.
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module
- PHY_PMA_CONTROL1, // PMA/PMD control register
+ /* Verify the PHY has come up by checking that the Reset bit has cleared. */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
+ PHY_PMA_CONTROL1, /* PMA/PMD control register */
&Value);
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
- if (Value & PMA_CONTROL1_RESET) // reset complete if bit is 0
+ if (Value & PMA_CONTROL1_RESET) /* reset complete if bit is 0 */
return (STATUS_FAILURE);
- // The SERDES should be initialized by now - confirm
+ /* The SERDES should be initialized by now - confirm */
READ_REG(HwRegs->LinkStatus, Value);
- if (Value & LS_SERDES_DOWN) // verify SERDES is initialized
+ if (Value & LS_SERDES_DOWN) /* verify SERDES is initialized */
return (STATUS_FAILURE);
- // The XAUI link should also be up - confirm
- if (!(Value & LS_XAUI_LINK_UP)) // verify XAUI link is up
+ /* The XAUI link should also be up - confirm */
+ if (!(Value & LS_XAUI_LINK_UP)) /* verify XAUI link is up */
return (STATUS_FAILURE);
- // Initialize the PHY
+ /* Initialize the PHY */
status = sxg_phy_init(adapter);
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
- // Enable the Link Alarm
- status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module
- LASI_CONTROL, // LASI control register
- LASI_CTL_LS_ALARM_ENABLE); // enable link alarm bit
+ /* Enable the Link Alarm */
+ status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
+ LASI_CONTROL, /* LASI control register */
+ LASI_CTL_LS_ALARM_ENABLE); /* enable link alarm bit */
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
- // XXXTODO - temporary - verify bit is set
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module
- LASI_CONTROL, // LASI control register
+ /* XXXTODO - temporary - verify bit is set */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
+ LASI_CONTROL, /* LASI control register */
&Value);
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
if (!(Value & LASI_CTL_LS_ALARM_ENABLE)) {
DBG_ERROR("Error! LASI Control Alarm Enable bit not set!\n");
}
- // Enable receive
+ /* Enable receive */
MaxFrame = adapter->JumboEnabled ? JUMBOMAXFRAME : ETHERMAXFRAME;
ConfigData = (RCV_CONFIG_ENABLE |
RCV_CONFIG_ENPARSE |
@@ -2256,7 +2257,7 @@ static int sxg_initialize_link(p_adapter_t adapter)
WRITE_REG(HwRegs->XmtConfig, XMT_CONFIG_ENABLE, TRUE);
- // Mark the link as down. We'll get a link event when it comes up.
+ /* Mark the link as down. We'll get a link event when it comes up. */
sxg_link_state(adapter, SXG_LINK_DOWN);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XInitLnk",
@@ -2279,35 +2280,35 @@ static int sxg_phy_init(p_adapter_t adapter)
PPHY_UCODE p;
int status;
- DBG_ERROR("ENTER %s\n", __FUNCTION__);
+ DBG_ERROR("ENTER %s\n", __func__);
- // Read a register to identify the PHY type
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module
- 0xC205, // PHY ID register (?)
- &Value); // XXXTODO - add def
+ /* Read a register to identify the PHY type */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
+ 0xC205, /* PHY ID register (?) */
+ &Value); /* XXXTODO - add def */
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
- if (Value == 0x0012) { // 0x0012 == AEL2005C PHY(?) - XXXTODO - add def
+ if (Value == 0x0012) { /* 0x0012 == AEL2005C PHY(?) - XXXTODO - add def */
DBG_ERROR
("AEL2005C PHY detected. Downloading PHY microcode.\n");
- // Initialize AEL2005C PHY and download PHY microcode
+ /* Initialize AEL2005C PHY and download PHY microcode */
for (p = PhyUcode; p->Addr != 0xFFFF; p++) {
if (p->Addr == 0) {
- // if address == 0, data == sleep time in ms
+ /* if address == 0, data == sleep time in ms */
mdelay(p->Data);
} else {
- // write the given data to the specified address
- status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module
- p->Addr, // PHY address
- p->Data); // PHY data
+ /* write the given data to the specified address */
+ status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
+ p->Addr, /* PHY address */
+ p->Data); /* PHY data */
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
}
}
}
- DBG_ERROR("EXIT %s\n", __FUNCTION__);
+ DBG_ERROR("EXIT %s\n", __func__);
return (STATUS_SUCCESS);
}
@@ -2330,42 +2331,42 @@ static void sxg_link_event(p_adapter_t adapter)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "LinkEvnt",
adapter, 0, 0, 0);
- DBG_ERROR("ENTER %s\n", __FUNCTION__);
+ DBG_ERROR("ENTER %s\n", __func__);
- // Check the Link Status register. We should have a Link Alarm.
+ /* Check the Link Status register. We should have a Link Alarm. */
READ_REG(HwRegs->LinkStatus, Value);
if (Value & LS_LINK_ALARM) {
- // We got a Link Status alarm. First, pause to let the
- // link state settle (it can bounce a number of times)
+ /* We got a Link Status alarm. First, pause to let the */
+ /* link state settle (it can bounce a number of times) */
mdelay(10);
- // Now clear the alarm by reading the LASI status register.
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module
- LASI_STATUS, // LASI status register
+ /* Now clear the alarm by reading the LASI status register. */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
+ LASI_STATUS, /* LASI status register */
&Value);
if (status != STATUS_SUCCESS) {
DBG_ERROR("Error reading LASI Status MDIO register!\n");
sxg_link_state(adapter, SXG_LINK_DOWN);
-// ASSERT(0);
+/* ASSERT(0); */
}
ASSERT(Value & LASI_STATUS_LS_ALARM);
- // Now get and set the link state
+ /* Now get and set the link state */
LinkState = sxg_get_link_state(adapter);
sxg_link_state(adapter, LinkState);
DBG_ERROR("SXG: Link Alarm occurred. Link is %s\n",
((LinkState == SXG_LINK_UP) ? "UP" : "DOWN"));
} else {
- // XXXTODO - Assuming Link Attention is only being generated for the
- // Link Alarm pin (and not for a XAUI Link Status change), then it's
- // impossible to get here. Yet we've gotten here twice (under extreme
- // conditions - bouncing the link up and down many times a second).
- // Needs further investigation.
+ /* XXXTODO - Assuming Link Attention is only being generated for the */
+ /* Link Alarm pin (and not for a XAUI Link Status change), then it's */
+ /* impossible to get here. Yet we've gotten here twice (under extreme */
+ /* conditions - bouncing the link up and down many times a second). */
+ /* Needs further investigation. */
DBG_ERROR("SXG: sxg_link_event: Can't get here!\n");
DBG_ERROR("SXG: Link Status == 0x%08X.\n", Value);
-// ASSERT(0);
+/* ASSERT(0); */
}
- DBG_ERROR("EXIT %s\n", __FUNCTION__);
+ DBG_ERROR("EXIT %s\n", __func__);
}
@@ -2383,50 +2384,50 @@ static SXG_LINK_STATE sxg_get_link_state(p_adapter_t adapter)
int status;
u32 Value;
- DBG_ERROR("ENTER %s\n", __FUNCTION__);
+ DBG_ERROR("ENTER %s\n", __func__);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "GetLink",
adapter, 0, 0, 0);
- // Per the Xenpak spec (and the IEEE 10Gb spec?), the link is up if
- // the following 3 bits (from 3 different MDIO registers) are all true.
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module
- PHY_PMA_RCV_DET, // PMA/PMD Receive Signal Detect register
+ /* Per the Xenpak spec (and the IEEE 10Gb spec?), the link is up if */
+ /* the following 3 bits (from 3 different MDIO registers) are all true. */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
+ PHY_PMA_RCV_DET, /* PMA/PMD Receive Signal Detect register */
&Value);
if (status != STATUS_SUCCESS)
goto bad;
- // If PMA/PMD receive signal detect is 0, then the link is down
+ /* If PMA/PMD receive signal detect is 0, then the link is down */
if (!(Value & PMA_RCV_DETECT))
return (SXG_LINK_DOWN);
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PCS, // PHY PCS module
- PHY_PCS_10G_STATUS1, // PCS 10GBASE-R Status 1 register
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PCS, /* PHY PCS module */
+ PHY_PCS_10G_STATUS1, /* PCS 10GBASE-R Status 1 register */
&Value);
if (status != STATUS_SUCCESS)
goto bad;
- // If PCS is not locked to receive blocks, then the link is down
+ /* If PCS is not locked to receive blocks, then the link is down */
if (!(Value & PCS_10B_BLOCK_LOCK))
return (SXG_LINK_DOWN);
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_XS, // PHY XS module
- PHY_XS_LANE_STATUS, // XS Lane Status register
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_XS, /* PHY XS module */
+ PHY_XS_LANE_STATUS, /* XS Lane Status register */
&Value);
if (status != STATUS_SUCCESS)
goto bad;
- // If XS transmit lanes are not aligned, then the link is down
+ /* If XS transmit lanes are not aligned, then the link is down */
if (!(Value & XS_LANE_ALIGN))
return (SXG_LINK_DOWN);
- // All 3 bits are true, so the link is up
- DBG_ERROR("EXIT %s\n", __FUNCTION__);
+ /* All 3 bits are true, so the link is up */
+ DBG_ERROR("EXIT %s\n", __func__);
return (SXG_LINK_UP);
bad:
- // An error occurred reading an MDIO register. This shouldn't happen.
+ /* An error occurred reading an MDIO register. This shouldn't happen. */
DBG_ERROR("Error reading an MDIO register!\n");
ASSERT(0);
return (SXG_LINK_DOWN);
@@ -2437,11 +2438,11 @@ static void sxg_indicate_link_state(p_adapter_t adapter,
{
if (adapter->LinkState == SXG_LINK_UP) {
DBG_ERROR("%s: LINK now UP, call netif_start_queue\n",
- __FUNCTION__);
+ __func__);
netif_start_queue(adapter->netdev);
} else {
DBG_ERROR("%s: LINK now DOWN, call netif_stop_queue\n",
- __FUNCTION__);
+ __func__);
netif_stop_queue(adapter->netdev);
}
}
@@ -2464,23 +2465,23 @@ static void sxg_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "LnkINDCT",
adapter, LinkState, adapter->LinkState, adapter->State);
- DBG_ERROR("ENTER %s\n", __FUNCTION__);
+ DBG_ERROR("ENTER %s\n", __func__);
- // Hold the adapter lock during this routine. Maybe move
- // the lock to the caller.
+ /* Hold the adapter lock during this routine. Maybe move */
+ /* the lock to the caller. */
spin_lock(&adapter->AdapterLock);
if (LinkState == adapter->LinkState) {
- // Nothing changed..
+ /* Nothing changed.. */
spin_unlock(&adapter->AdapterLock);
- DBG_ERROR("EXIT #0 %s\n", __FUNCTION__);
+ DBG_ERROR("EXIT #0 %s\n", __func__);
return;
}
- // Save the adapter state
+ /* Save the adapter state */
adapter->LinkState = LinkState;
- // Drop the lock and indicate link state
+ /* Drop the lock and indicate link state */
spin_unlock(&adapter->AdapterLock);
- DBG_ERROR("EXIT #1 %s\n", __FUNCTION__);
+ DBG_ERROR("EXIT #1 %s\n", __func__);
sxg_indicate_link_state(adapter, LinkState);
}
@@ -2501,76 +2502,76 @@ static int sxg_write_mdio_reg(p_adapter_t adapter,
u32 DevAddr, u32 RegAddr, u32 Value)
{
PSXG_HW_REGS HwRegs = adapter->HwRegs;
- u32 AddrOp; // Address operation (written to MIIM field reg)
- u32 WriteOp; // Write operation (written to MIIM field reg)
- u32 Cmd; // Command (written to MIIM command reg)
+ u32 AddrOp; /* Address operation (written to MIIM field reg) */
+ u32 WriteOp; /* Write operation (written to MIIM field reg) */
+ u32 Cmd; /* Command (written to MIIM command reg) */
u32 ValueRead;
u32 Timeout;
-// DBG_ERROR("ENTER %s\n", __FUNCTION__);
+/* DBG_ERROR("ENTER %s\n", __func__); */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "WrtMDIO",
adapter, 0, 0, 0);
- // Ensure values don't exceed field width
- DevAddr &= 0x001F; // 5-bit field
- RegAddr &= 0xFFFF; // 16-bit field
- Value &= 0xFFFF; // 16-bit field
+ /* Ensure values don't exceed field width */
+ DevAddr &= 0x001F; /* 5-bit field */
+ RegAddr &= 0xFFFF; /* 16-bit field */
+ Value &= 0xFFFF; /* 16-bit field */
- // Set MIIM field register bits for an MIIM address operation
+ /* Set MIIM field register bits for an MIIM address operation */
AddrOp = (MIIM_PORT_NUM << AXGMAC_AMIIM_FIELD_PORT_SHIFT) |
(DevAddr << AXGMAC_AMIIM_FIELD_DEV_SHIFT) |
(MIIM_TA_10GB << AXGMAC_AMIIM_FIELD_TA_SHIFT) |
(MIIM_OP_ADDR << AXGMAC_AMIIM_FIELD_OP_SHIFT) | RegAddr;
- // Set MIIM field register bits for an MIIM write operation
+ /* Set MIIM field register bits for an MIIM write operation */
WriteOp = (MIIM_PORT_NUM << AXGMAC_AMIIM_FIELD_PORT_SHIFT) |
(DevAddr << AXGMAC_AMIIM_FIELD_DEV_SHIFT) |
(MIIM_TA_10GB << AXGMAC_AMIIM_FIELD_TA_SHIFT) |
(MIIM_OP_WRITE << AXGMAC_AMIIM_FIELD_OP_SHIFT) | Value;
- // Set MIIM command register bits to execute an MIIM command
+ /* Set MIIM command register bits to execute an MIIM command */
Cmd = AXGMAC_AMIIM_CMD_START | AXGMAC_AMIIM_CMD_10G_OPERATION;
- // Reset the command register command bit (in case it's not 0)
+ /* Reset the command register command bit (in case it's not 0) */
WRITE_REG(HwRegs->MacAmiimCmd, 0, TRUE);
- // MIIM write to set the address of the specified MDIO register
+ /* MIIM write to set the address of the specified MDIO register */
WRITE_REG(HwRegs->MacAmiimField, AddrOp, TRUE);
- // Write to MIIM Command Register to execute to address operation
+ /* Write to MIIM Command Register to execute to address operation */
WRITE_REG(HwRegs->MacAmiimCmd, Cmd, TRUE);
- // Poll AMIIM Indicator register to wait for completion
+ /* Poll AMIIM Indicator register to wait for completion */
Timeout = SXG_LINK_TIMEOUT;
do {
- udelay(100); // Timeout in 100us units
+ udelay(100); /* Timeout in 100us units */
READ_REG(HwRegs->MacAmiimIndicator, ValueRead);
if (--Timeout == 0) {
return (STATUS_FAILURE);
}
} while (ValueRead & AXGMAC_AMIIM_INDC_BUSY);
- // Reset the command register command bit
+ /* Reset the command register command bit */
WRITE_REG(HwRegs->MacAmiimCmd, 0, TRUE);
- // MIIM write to set up an MDIO write operation
+ /* MIIM write to set up an MDIO write operation */
WRITE_REG(HwRegs->MacAmiimField, WriteOp, TRUE);
- // Write to MIIM Command Register to execute the write operation
+ /* Write to MIIM Command Register to execute the write operation */
WRITE_REG(HwRegs->MacAmiimCmd, Cmd, TRUE);
- // Poll AMIIM Indicator register to wait for completion
+ /* Poll AMIIM Indicator register to wait for completion */
Timeout = SXG_LINK_TIMEOUT;
do {
- udelay(100); // Timeout in 100us units
+ udelay(100); /* Timeout in 100us units */
READ_REG(HwRegs->MacAmiimIndicator, ValueRead);
if (--Timeout == 0) {
return (STATUS_FAILURE);
}
} while (ValueRead & AXGMAC_AMIIM_INDC_BUSY);
-// DBG_ERROR("EXIT %s\n", __FUNCTION__);
+/* DBG_ERROR("EXIT %s\n", __func__); */
return (STATUS_SUCCESS);
}
@@ -2591,110 +2592,78 @@ static int sxg_read_mdio_reg(p_adapter_t adapter,
u32 DevAddr, u32 RegAddr, u32 *pValue)
{
PSXG_HW_REGS HwRegs = adapter->HwRegs;
- u32 AddrOp; // Address operation (written to MIIM field reg)
- u32 ReadOp; // Read operation (written to MIIM field reg)
- u32 Cmd; // Command (written to MIIM command reg)
+ u32 AddrOp; /* Address operation (written to MIIM field reg) */
+ u32 ReadOp; /* Read operation (written to MIIM field reg) */
+ u32 Cmd; /* Command (written to MIIM command reg) */
u32 ValueRead;
u32 Timeout;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "WrtMDIO",
adapter, 0, 0, 0);
-// DBG_ERROR("ENTER %s\n", __FUNCTION__);
+/* DBG_ERROR("ENTER %s\n", __func__); */
- // Ensure values don't exceed field width
- DevAddr &= 0x001F; // 5-bit field
- RegAddr &= 0xFFFF; // 16-bit field
+ /* Ensure values don't exceed field width */
+ DevAddr &= 0x001F; /* 5-bit field */
+ RegAddr &= 0xFFFF; /* 16-bit field */
- // Set MIIM field register bits for an MIIM address operation
+ /* Set MIIM field register bits for an MIIM address operation */
AddrOp = (MIIM_PORT_NUM << AXGMAC_AMIIM_FIELD_PORT_SHIFT) |
(DevAddr << AXGMAC_AMIIM_FIELD_DEV_SHIFT) |
(MIIM_TA_10GB << AXGMAC_AMIIM_FIELD_TA_SHIFT) |
(MIIM_OP_ADDR << AXGMAC_AMIIM_FIELD_OP_SHIFT) | RegAddr;
- // Set MIIM field register bits for an MIIM read operation
+ /* Set MIIM field register bits for an MIIM read operation */
ReadOp = (MIIM_PORT_NUM << AXGMAC_AMIIM_FIELD_PORT_SHIFT) |
(DevAddr << AXGMAC_AMIIM_FIELD_DEV_SHIFT) |
(MIIM_TA_10GB << AXGMAC_AMIIM_FIELD_TA_SHIFT) |
(MIIM_OP_READ << AXGMAC_AMIIM_FIELD_OP_SHIFT);
- // Set MIIM command register bits to execute an MIIM command
+ /* Set MIIM command register bits to execute an MIIM command */
Cmd = AXGMAC_AMIIM_CMD_START | AXGMAC_AMIIM_CMD_10G_OPERATION;
- // Reset the command register command bit (in case it's not 0)
+ /* Reset the command register command bit (in case it's not 0) */
WRITE_REG(HwRegs->MacAmiimCmd, 0, TRUE);
- // MIIM write to set the address of the specified MDIO register
+ /* MIIM write to set the address of the specified MDIO register */
WRITE_REG(HwRegs->MacAmiimField, AddrOp, TRUE);
- // Write to MIIM Command Register to execute to address operation
+ /* Write to MIIM Command Register to execute to address operation */
WRITE_REG(HwRegs->MacAmiimCmd, Cmd, TRUE);
- // Poll AMIIM Indicator register to wait for completion
+ /* Poll AMIIM Indicator register to wait for completion */
Timeout = SXG_LINK_TIMEOUT;
do {
- udelay(100); // Timeout in 100us units
+ udelay(100); /* Timeout in 100us units */
READ_REG(HwRegs->MacAmiimIndicator, ValueRead);
if (--Timeout == 0) {
return (STATUS_FAILURE);
}
} while (ValueRead & AXGMAC_AMIIM_INDC_BUSY);
- // Reset the command register command bit
+ /* Reset the command register command bit */
WRITE_REG(HwRegs->MacAmiimCmd, 0, TRUE);
- // MIIM write to set up an MDIO register read operation
+ /* MIIM write to set up an MDIO register read operation */
WRITE_REG(HwRegs->MacAmiimField, ReadOp, TRUE);
- // Write to MIIM Command Register to execute the read operation
+ /* Write to MIIM Command Register to execute the read operation */
WRITE_REG(HwRegs->MacAmiimCmd, Cmd, TRUE);
- // Poll AMIIM Indicator register to wait for completion
+ /* Poll AMIIM Indicator register to wait for completion */
Timeout = SXG_LINK_TIMEOUT;
do {
- udelay(100); // Timeout in 100us units
+ udelay(100); /* Timeout in 100us units */
READ_REG(HwRegs->MacAmiimIndicator, ValueRead);
if (--Timeout == 0) {
return (STATUS_FAILURE);
}
} while (ValueRead & AXGMAC_AMIIM_INDC_BUSY);
- // Read the MDIO register data back from the field register
+ /* Read the MDIO register data back from the field register */
READ_REG(HwRegs->MacAmiimField, *pValue);
- *pValue &= 0xFFFF; // data is in the lower 16 bits
+ *pValue &= 0xFFFF; /* data is in the lower 16 bits */
-// DBG_ERROR("EXIT %s\n", __FUNCTION__);
-
- return (STATUS_SUCCESS);
-}
-
-/*
- * Allocate a mcast_address structure to hold the multicast address.
- * Link it in.
- */
-static int sxg_mcast_add_list(p_adapter_t adapter, char *address)
-{
- p_mcast_address_t mcaddr, mlist;
- bool equaladdr;
-
- /* Check to see if it already exists */
- mlist = adapter->mcastaddrs;
- while (mlist) {
- ETHER_EQ_ADDR(mlist->address, address, equaladdr);
- if (equaladdr) {
- return (STATUS_SUCCESS);
- }
- mlist = mlist->next;
- }
-
- /* Doesn't already exist. Allocate a structure to hold it */
- mcaddr = kmalloc(sizeof(mcast_address_t), GFP_ATOMIC);
- if (mcaddr == NULL)
- return 1;
-
- memcpy(mcaddr->address, address, 6);
-
- mcaddr->next = adapter->mcastaddrs;
- adapter->mcastaddrs = mcaddr;
+/* DBG_ERROR("EXIT %s\n", __func__); */
return (STATUS_SUCCESS);
}
@@ -2710,7 +2679,6 @@ static int sxg_mcast_add_list(p_adapter_t adapter, char *address)
*
*/
static u32 sxg_crc_table[256]; /* Table of CRC's for all possible byte values */
-static u32 sxg_crc_init; /* Is table initialized */
/*
* Contruct the CRC32 table
@@ -2737,6 +2705,8 @@ static void sxg_mcast_init_crc32(void)
}
}
+#if XXXTODO
+static u32 sxg_crc_init; /* Is table initialized */
/*
* Return the MAC hast as described above.
*/
@@ -2765,6 +2735,74 @@ static unsigned char sxg_mcast_get_mac_hash(char *macaddr)
return (machash);
}
+static void sxg_mcast_set_mask(p_adapter_t adapter)
+{
+ PSXG_UCODE_REGS sxg_regs = adapter->UcodeRegs;
+
+ DBG_ERROR("%s ENTER (%s) macopts[%x] mask[%llx]\n", __func__,
+ adapter->netdev->name, (unsigned int)adapter->MacFilter,
+ adapter->MulticastMask);
+
+ if (adapter->MacFilter & (MAC_ALLMCAST | MAC_PROMISC)) {
+ /* Turn on all multicast addresses. We have to do this for promiscuous
+ * mode as well as ALLMCAST mode. It saves the Microcode from having
+ * to keep state about the MAC configuration.
+ */
+/* DBG_ERROR("sxg: %s macopts = MAC_ALLMCAST | MAC_PROMISC\n SLUT MODE!!!\n",__func__); */
+ WRITE_REG(sxg_regs->McastLow, 0xFFFFFFFF, FLUSH);
+ WRITE_REG(sxg_regs->McastHigh, 0xFFFFFFFF, FLUSH);
+/* DBG_ERROR("%s (%s) WRITE to slic_regs slic_mcastlow&high 0xFFFFFFFF\n",__func__, adapter->netdev->name); */
+
+ } else {
+ /* Commit our multicast mast to the SLIC by writing to the multicast
+ * address mask registers
+ */
+ DBG_ERROR("%s (%s) WRITE mcastlow[%lx] mcasthigh[%lx]\n",
+ __func__, adapter->netdev->name,
+ ((ulong) (adapter->MulticastMask & 0xFFFFFFFF)),
+ ((ulong)
+ ((adapter->MulticastMask >> 32) & 0xFFFFFFFF)));
+
+ WRITE_REG(sxg_regs->McastLow,
+ (u32) (adapter->MulticastMask & 0xFFFFFFFF), FLUSH);
+ WRITE_REG(sxg_regs->McastHigh,
+ (u32) ((adapter->
+ MulticastMask >> 32) & 0xFFFFFFFF), FLUSH);
+ }
+}
+
+/*
+ * Allocate a mcast_address structure to hold the multicast address.
+ * Link it in.
+ */
+static int sxg_mcast_add_list(p_adapter_t adapter, char *address)
+{
+ p_mcast_address_t mcaddr, mlist;
+ bool equaladdr;
+
+ /* Check to see if it already exists */
+ mlist = adapter->mcastaddrs;
+ while (mlist) {
+ ETHER_EQ_ADDR(mlist->address, address, equaladdr);
+ if (equaladdr) {
+ return (STATUS_SUCCESS);
+ }
+ mlist = mlist->next;
+ }
+
+ /* Doesn't already exist. Allocate a structure to hold it */
+ mcaddr = kmalloc(sizeof(mcast_address_t), GFP_ATOMIC);
+ if (mcaddr == NULL)
+ return 1;
+
+ memcpy(mcaddr->address, address, 6);
+
+ mcaddr->next = adapter->mcastaddrs;
+ adapter->mcastaddrs = mcaddr;
+
+ return (STATUS_SUCCESS);
+}
+
static void sxg_mcast_set_bit(p_adapter_t adapter, char *address)
{
unsigned char crcpoly;
@@ -2783,7 +2821,6 @@ static void sxg_mcast_set_bit(p_adapter_t adapter, char *address)
static void sxg_mcast_set_list(p_net_device dev)
{
-#if XXXTODO
p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
int status = STATUS_SUCCESS;
int i;
@@ -2809,7 +2846,7 @@ static void sxg_mcast_set_list(p_net_device dev)
}
DBG_ERROR("%s a->devflags_prev[%x] dev->flags[%x] status[%x]\n",
- __FUNCTION__, adapter->devflags_prev, dev->flags, status);
+ __func__, adapter->devflags_prev, dev->flags, status);
if (adapter->devflags_prev != dev->flags) {
adapter->macopts = MAC_DIRECTED;
if (dev->flags) {
@@ -2828,60 +2865,24 @@ static void sxg_mcast_set_list(p_net_device dev)
}
adapter->devflags_prev = dev->flags;
DBG_ERROR("%s call sxg_config_set adapter->macopts[%x]\n",
- __FUNCTION__, adapter->macopts);
+ __func__, adapter->macopts);
sxg_config_set(adapter, TRUE);
} else {
if (status == STATUS_SUCCESS) {
sxg_mcast_set_mask(adapter);
}
}
-#endif
return;
}
-
-static void sxg_mcast_set_mask(p_adapter_t adapter)
-{
- PSXG_UCODE_REGS sxg_regs = adapter->UcodeRegs;
-
- DBG_ERROR("%s ENTER (%s) macopts[%x] mask[%llx]\n", __FUNCTION__,
- adapter->netdev->name, (unsigned int)adapter->MacFilter,
- adapter->MulticastMask);
-
- if (adapter->MacFilter & (MAC_ALLMCAST | MAC_PROMISC)) {
- /* Turn on all multicast addresses. We have to do this for promiscuous
- * mode as well as ALLMCAST mode. It saves the Microcode from having
- * to keep state about the MAC configuration.
- */
-// DBG_ERROR("sxg: %s macopts = MAC_ALLMCAST | MAC_PROMISC\n SLUT MODE!!!\n",__FUNCTION__);
- WRITE_REG(sxg_regs->McastLow, 0xFFFFFFFF, FLUSH);
- WRITE_REG(sxg_regs->McastHigh, 0xFFFFFFFF, FLUSH);
-// DBG_ERROR("%s (%s) WRITE to slic_regs slic_mcastlow&high 0xFFFFFFFF\n",__FUNCTION__, adapter->netdev->name);
-
- } else {
- /* Commit our multicast mast to the SLIC by writing to the multicast
- * address mask registers
- */
- DBG_ERROR("%s (%s) WRITE mcastlow[%lx] mcasthigh[%lx]\n",
- __FUNCTION__, adapter->netdev->name,
- ((ulong) (adapter->MulticastMask & 0xFFFFFFFF)),
- ((ulong)
- ((adapter->MulticastMask >> 32) & 0xFFFFFFFF)));
-
- WRITE_REG(sxg_regs->McastLow,
- (u32) (adapter->MulticastMask & 0xFFFFFFFF), FLUSH);
- WRITE_REG(sxg_regs->McastHigh,
- (u32) ((adapter->
- MulticastMask >> 32) & 0xFFFFFFFF), FLUSH);
- }
-}
+#endif
static void sxg_unmap_mmio_space(p_adapter_t adapter)
{
#if LINUX_FREES_ADAPTER_RESOURCES
-// if (adapter->Regs) {
-// iounmap(adapter->Regs);
-// }
-// adapter->slic_regs = NULL;
+/* if (adapter->Regs) { */
+/* iounmap(adapter->Regs); */
+/* } */
+/* adapter->slic_regs = NULL; */
#endif
}
@@ -2909,8 +2910,8 @@ void SxgFreeResources(p_adapter_t adapter)
IsrCount = adapter->MsiEnabled ? RssIds : 1;
if (adapter->BasicAllocations == FALSE) {
- // No allocations have been made, including spinlocks,
- // or listhead initializations. Return.
+ /* No allocations have been made, including spinlocks, */
+ /* or listhead initializations. Return. */
return;
}
@@ -2920,7 +2921,7 @@ void SxgFreeResources(p_adapter_t adapter)
if (!(IsListEmpty(&adapter->AllSglBuffers))) {
SxgFreeSglBuffers(adapter);
}
- // Free event queues.
+ /* Free event queues. */
if (adapter->EventRings) {
pci_free_consistent(adapter->pcidev,
sizeof(SXG_EVENT_RING) * RssIds,
@@ -2947,17 +2948,17 @@ void SxgFreeResources(p_adapter_t adapter)
SXG_FREE_PACKET_POOL(adapter->PacketPoolHandle);
SXG_FREE_BUFFER_POOL(adapter->BufferPoolHandle);
- // Unmap register spaces
+ /* Unmap register spaces */
SxgUnmapResources(adapter);
- // Deregister DMA
+ /* Deregister DMA */
if (adapter->DmaHandle) {
SXG_DEREGISTER_DMA(adapter->DmaHandle);
}
- // Deregister interrupt
+ /* Deregister interrupt */
SxgDeregisterInterrupt(adapter);
- // Possibly free system info (5.2 only)
+ /* Possibly free system info (5.2 only) */
SXG_RELEASE_SYSTEM_INFO(adapter);
SxgDiagFreeResources(adapter);
@@ -3047,23 +3048,23 @@ static int sxg_allocate_buffer_memory(p_adapter_t adapter,
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocMem",
adapter, Size, BufferType, 0);
- // Grab the adapter lock and check the state.
- // If we're in anything other than INITIALIZING or
- // RUNNING state, fail. This is to prevent
- // allocations in an improper driver state
+ /* Grab the adapter lock and check the state. */
+ /* If we're in anything other than INITIALIZING or */
+ /* RUNNING state, fail. This is to prevent */
+ /* allocations in an improper driver state */
spin_lock(&adapter->AdapterLock);
- // Increment the AllocationsPending count while holding
- // the lock. Pause processing relies on this
+ /* Increment the AllocationsPending count while holding */
+ /* the lock. Pause processing relies on this */
++adapter->AllocationsPending;
spin_unlock(&adapter->AdapterLock);
- // At initialization time allocate resources synchronously.
+ /* At initialization time allocate resources synchronously. */
Buffer = pci_alloc_consistent(adapter->pcidev, Size, &pBuffer);
if (Buffer == NULL) {
spin_lock(&adapter->AdapterLock);
- // Decrement the AllocationsPending count while holding
- // the lock. Pause processing relies on this
+ /* Decrement the AllocationsPending count while holding */
+ /* the lock. Pause processing relies on this */
--adapter->AllocationsPending;
spin_unlock(&adapter->AdapterLock);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlcMemF1",
@@ -3113,10 +3114,10 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
ASSERT((BufferSize == SXG_RCV_DATA_BUFFER_SIZE) ||
(BufferSize == SXG_RCV_JUMBO_BUFFER_SIZE));
ASSERT(Length == SXG_RCV_BLOCK_SIZE(BufferSize));
- // First, initialize the contained pool of receive data
- // buffers. This initialization requires NBL/NB/MDL allocations,
- // If any of them fail, free the block and return without
- // queueing the shared memory
+ /* First, initialize the contained pool of receive data */
+ /* buffers. This initialization requires NBL/NB/MDL allocations, */
+ /* If any of them fail, free the block and return without */
+ /* queueing the shared memory */
RcvDataBuffer = RcvBlock;
#if 0
for (i = 0, Paddr = *PhysicalAddress;
@@ -3126,14 +3127,14 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
for (i = 0, Paddr = PhysicalAddress;
i < SXG_RCV_DESCRIPTORS_PER_BLOCK;
i++, Paddr += BufferSize, RcvDataBuffer += BufferSize) {
- //
+ /* */
RcvDataBufferHdr =
(PSXG_RCV_DATA_BUFFER_HDR) (RcvDataBuffer +
SXG_RCV_DATA_BUFFER_HDR_OFFSET
(BufferSize));
RcvDataBufferHdr->VirtualAddress = RcvDataBuffer;
RcvDataBufferHdr->PhysicalAddress = Paddr;
- RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM; // For FREE macro assertion
+ RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM; /* For FREE macro assertion */
RcvDataBufferHdr->Size =
SXG_RCV_BUFFER_DATA_SIZE(BufferSize);
@@ -3143,8 +3144,8 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
}
- // Place this entire block of memory on the AllRcvBlocks queue so it can be
- // free later
+ /* Place this entire block of memory on the AllRcvBlocks queue so it can be */
+ /* free later */
RcvBlockHdr =
(PSXG_RCV_BLOCK_HDR) ((unsigned char *)RcvBlock +
SXG_RCV_BLOCK_HDR_OFFSET(BufferSize));
@@ -3155,7 +3156,7 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
InsertTailList(&adapter->AllRcvBlocks, &RcvBlockHdr->AllList);
spin_unlock(&adapter->RcvQLock);
- // Now free the contained receive data buffers that we initialized above
+ /* Now free the contained receive data buffers that we initialized above */
RcvDataBuffer = RcvBlock;
for (i = 0, Paddr = PhysicalAddress;
i < SXG_RCV_DESCRIPTORS_PER_BLOCK;
@@ -3168,7 +3169,7 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
spin_unlock(&adapter->RcvQLock);
}
- // Locate the descriptor block and put it on a separate free queue
+ /* Locate the descriptor block and put it on a separate free queue */
RcvDescriptorBlock =
(PSXG_RCV_DESCRIPTOR_BLOCK) ((unsigned char *)RcvBlock +
SXG_RCV_DESCRIPTOR_BLOCK_OFFSET
@@ -3186,7 +3187,7 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
adapter, RcvBlock, Length, 0);
return;
fail:
- // Free any allocated resources
+ /* Free any allocated resources */
if (RcvBlock) {
RcvDataBuffer = RcvBlock;
for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK;
@@ -3200,7 +3201,7 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
pci_free_consistent(adapter->pcidev,
Length, RcvBlock, PhysicalAddress);
}
- DBG_ERROR("%s: OUT OF RESOURCES\n", __FUNCTION__);
+ DBG_ERROR("%s: OUT OF RESOURCES\n", __func__);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "RcvAFail",
adapter, adapter->FreeRcvBufferCount,
adapter->FreeRcvBlockCount, adapter->AllRcvBlockCount);
@@ -3230,7 +3231,7 @@ static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter,
adapter->AllSglBufferCount++;
memset(SxgSgl, 0, sizeof(SXG_SCATTER_GATHER));
SxgSgl->PhysicalAddress = PhysicalAddress; /* *PhysicalAddress; */
- SxgSgl->adapter = adapter; // Initialize backpointer once
+ SxgSgl->adapter = adapter; /* Initialize backpointer once */
InsertTailList(&adapter->AllSglBuffers, &SxgSgl->AllList);
spin_unlock(&adapter->SglQLock);
SxgSgl->State = SXG_BUFFER_BUSY;
@@ -3244,14 +3245,14 @@ static unsigned char temp_mac_address[6] =
static void sxg_adapter_set_hwaddr(p_adapter_t adapter)
{
-// DBG_ERROR ("%s ENTER card->config_set[%x] port[%d] physport[%d] funct#[%d]\n", __FUNCTION__,
-// card->config_set, adapter->port, adapter->physport, adapter->functionnumber);
-//
-// sxg_dbg_macaddrs(adapter);
+/* DBG_ERROR ("%s ENTER card->config_set[%x] port[%d] physport[%d] funct#[%d]\n", __func__, */
+/* card->config_set, adapter->port, adapter->physport, adapter->functionnumber); */
+/* */
+/* sxg_dbg_macaddrs(adapter); */
memcpy(adapter->macaddr, temp_mac_address, sizeof(SXG_CONFIG_MAC));
-// DBG_ERROR ("%s AFTER copying from config.macinfo into currmacaddr\n", __FUNCTION__);
-// sxg_dbg_macaddrs(adapter);
+/* DBG_ERROR ("%s AFTER copying from config.macinfo into currmacaddr\n", __func__); */
+/* sxg_dbg_macaddrs(adapter); */
if (!(adapter->currmacaddr[0] ||
adapter->currmacaddr[1] ||
adapter->currmacaddr[2] ||
@@ -3262,18 +3263,18 @@ static void sxg_adapter_set_hwaddr(p_adapter_t adapter)
if (adapter->netdev) {
memcpy(adapter->netdev->dev_addr, adapter->currmacaddr, 6);
}
-// DBG_ERROR ("%s EXIT port %d\n", __FUNCTION__, adapter->port);
+/* DBG_ERROR ("%s EXIT port %d\n", __func__, adapter->port); */
sxg_dbg_macaddrs(adapter);
}
+#if XXXTODO
static int sxg_mac_set_address(p_net_device dev, void *ptr)
{
-#if XXXTODO
p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
struct sockaddr *addr = ptr;
- DBG_ERROR("%s ENTER (%s)\n", __FUNCTION__, adapter->netdev->name);
+ DBG_ERROR("%s ENTER (%s)\n", __func__, adapter->netdev->name);
if (netif_running(dev)) {
return -EBUSY;
@@ -3282,22 +3283,22 @@ static int sxg_mac_set_address(p_net_device dev, void *ptr)
return -EBUSY;
}
DBG_ERROR("sxg: %s (%s) curr %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
- __FUNCTION__, adapter->netdev->name, adapter->currmacaddr[0],
+ __func__, adapter->netdev->name, adapter->currmacaddr[0],
adapter->currmacaddr[1], adapter->currmacaddr[2],
adapter->currmacaddr[3], adapter->currmacaddr[4],
adapter->currmacaddr[5]);
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
memcpy(adapter->currmacaddr, addr->sa_data, dev->addr_len);
DBG_ERROR("sxg: %s (%s) new %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
- __FUNCTION__, adapter->netdev->name, adapter->currmacaddr[0],
+ __func__, adapter->netdev->name, adapter->currmacaddr[0],
adapter->currmacaddr[1], adapter->currmacaddr[2],
adapter->currmacaddr[3], adapter->currmacaddr[4],
adapter->currmacaddr[5]);
sxg_config_set(adapter, TRUE);
-#endif
return 0;
}
+#endif
/*****************************************************************************/
/************* SXG DRIVER FUNCTIONS (below) ********************************/
@@ -3321,77 +3322,77 @@ static int sxg_initialize_adapter(p_adapter_t adapter)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "InitAdpt",
adapter, 0, 0, 0);
- RssIds = 1; // XXXTODO SXG_RSS_CPU_COUNT(adapter);
+ RssIds = 1; /* XXXTODO SXG_RSS_CPU_COUNT(adapter); */
IsrCount = adapter->MsiEnabled ? RssIds : 1;
- // Sanity check SXG_UCODE_REGS structure definition to
- // make sure the length is correct
+ /* Sanity check SXG_UCODE_REGS structure definition to */
+ /* make sure the length is correct */
ASSERT(sizeof(SXG_UCODE_REGS) == SXG_REGISTER_SIZE_PER_CPU);
- // Disable interrupts
+ /* Disable interrupts */
SXG_DISABLE_ALL_INTERRUPTS(adapter);
- // Set MTU
+ /* Set MTU */
ASSERT((adapter->FrameSize == ETHERMAXFRAME) ||
(adapter->FrameSize == JUMBOMAXFRAME));
WRITE_REG(adapter->UcodeRegs[0].LinkMtu, adapter->FrameSize, TRUE);
- // Set event ring base address and size
+ /* Set event ring base address and size */
WRITE_REG64(adapter,
adapter->UcodeRegs[0].EventBase, adapter->PEventRings, 0);
WRITE_REG(adapter->UcodeRegs[0].EventSize, EVENT_RING_SIZE, TRUE);
- // Per-ISR initialization
+ /* Per-ISR initialization */
for (i = 0; i < IsrCount; i++) {
u64 Addr;
- // Set interrupt status pointer
+ /* Set interrupt status pointer */
Addr = adapter->PIsr + (i * sizeof(u32));
WRITE_REG64(adapter, adapter->UcodeRegs[i].Isp, Addr, i);
}
- // XMT ring zero index
+ /* XMT ring zero index */
WRITE_REG64(adapter,
adapter->UcodeRegs[0].SPSendIndex,
adapter->PXmtRingZeroIndex, 0);
- // Per-RSS initialization
+ /* Per-RSS initialization */
for (i = 0; i < RssIds; i++) {
- // Release all event ring entries to the Microcode
+ /* Release all event ring entries to the Microcode */
WRITE_REG(adapter->UcodeRegs[i].EventRelease, EVENT_RING_SIZE,
TRUE);
}
- // Transmit ring base and size
+ /* Transmit ring base and size */
WRITE_REG64(adapter,
adapter->UcodeRegs[0].XmtBase, adapter->PXmtRings, 0);
WRITE_REG(adapter->UcodeRegs[0].XmtSize, SXG_XMT_RING_SIZE, TRUE);
- // Receive ring base and size
+ /* Receive ring base and size */
WRITE_REG64(adapter,
adapter->UcodeRegs[0].RcvBase, adapter->PRcvRings, 0);
WRITE_REG(adapter->UcodeRegs[0].RcvSize, SXG_RCV_RING_SIZE, TRUE);
- // Populate the card with receive buffers
+ /* Populate the card with receive buffers */
sxg_stock_rcv_buffers(adapter);
- // Initialize checksum offload capabilities. At the moment
- // we always enable IP and TCP receive checksums on the card.
- // Depending on the checksum configuration specified by the
- // user, we can choose to report or ignore the checksum
- // information provided by the card.
+ /* Initialize checksum offload capabilities. At the moment */
+ /* we always enable IP and TCP receive checksums on the card. */
+ /* Depending on the checksum configuration specified by the */
+ /* user, we can choose to report or ignore the checksum */
+ /* information provided by the card. */
WRITE_REG(adapter->UcodeRegs[0].ReceiveChecksum,
SXG_RCV_TCP_CSUM_ENABLED | SXG_RCV_IP_CSUM_ENABLED, TRUE);
- // Initialize the MAC, XAUI
- DBG_ERROR("sxg: %s ENTER sxg_initialize_link\n", __FUNCTION__);
+ /* Initialize the MAC, XAUI */
+ DBG_ERROR("sxg: %s ENTER sxg_initialize_link\n", __func__);
status = sxg_initialize_link(adapter);
- DBG_ERROR("sxg: %s EXIT sxg_initialize_link status[%x]\n", __FUNCTION__,
+ DBG_ERROR("sxg: %s EXIT sxg_initialize_link status[%x]\n", __func__,
status);
if (status != STATUS_SUCCESS) {
return (status);
}
- // Initialize Dead to FALSE.
- // SlicCheckForHang or SlicDumpThread will take it from here.
+ /* Initialize Dead to FALSE. */
+ /* SlicCheckForHang or SlicDumpThread will take it from here. */
adapter->Dead = FALSE;
adapter->PingOutstanding = FALSE;
@@ -3428,14 +3429,14 @@ static int sxg_fill_descriptor_block(p_adapter_t adapter,
ASSERT(RcvDescriptorBlockHdr);
- // If we don't have the resources to fill the descriptor block,
- // return failure
+ /* If we don't have the resources to fill the descriptor block, */
+ /* return failure */
if ((adapter->FreeRcvBufferCount < SXG_RCV_DESCRIPTORS_PER_BLOCK) ||
SXG_RING_FULL(RcvRingInfo)) {
adapter->Stats.NoMem++;
return (STATUS_FAILURE);
}
- // Get a ring descriptor command
+ /* Get a ring descriptor command */
SXG_GET_CMD(RingZero,
RcvRingInfo, RingDescriptorCmd, RcvDescriptorBlockHdr);
ASSERT(RingDescriptorCmd);
@@ -3443,7 +3444,7 @@ static int sxg_fill_descriptor_block(p_adapter_t adapter,
RcvDescriptorBlock =
(PSXG_RCV_DESCRIPTOR_BLOCK) RcvDescriptorBlockHdr->VirtualAddress;
- // Fill in the descriptor block
+ /* Fill in the descriptor block */
for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK; i++) {
SXG_GET_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr);
ASSERT(RcvDataBufferHdr);
@@ -3454,13 +3455,13 @@ static int sxg_fill_descriptor_block(p_adapter_t adapter,
RcvDescriptorBlock->Descriptors[i].PhysicalAddress =
RcvDataBufferHdr->PhysicalAddress;
}
- // Add the descriptor block to receive descriptor ring 0
+ /* Add the descriptor block to receive descriptor ring 0 */
RingDescriptorCmd->Sgl = RcvDescriptorBlockHdr->PhysicalAddress;
- // RcvBuffersOnCard is not protected via the receive lock (see
- // sxg_process_event_queue) We don't want to grap a lock every time a
- // buffer is returned to us, so we use atomic interlocked functions
- // instead.
+ /* RcvBuffersOnCard is not protected via the receive lock (see */
+ /* sxg_process_event_queue) We don't want to grap a lock every time a */
+ /* buffer is returned to us, so we use atomic interlocked functions */
+ /* instead. */
adapter->RcvBuffersOnCard += SXG_RCV_DESCRIPTORS_PER_BLOCK;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DscBlk",
@@ -3490,10 +3491,10 @@ static void sxg_stock_rcv_buffers(p_adapter_t adapter)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "StockBuf",
adapter, adapter->RcvBuffersOnCard,
adapter->FreeRcvBufferCount, adapter->AllRcvBlockCount);
- // First, see if we've got less than our minimum threshold of
- // receive buffers, there isn't an allocation in progress, and
- // we haven't exceeded our maximum.. get another block of buffers
- // None of this needs to be SMP safe. It's round numbers.
+ /* First, see if we've got less than our minimum threshold of */
+ /* receive buffers, there isn't an allocation in progress, and */
+ /* we haven't exceeded our maximum.. get another block of buffers */
+ /* None of this needs to be SMP safe. It's round numbers. */
if ((adapter->FreeRcvBufferCount < SXG_MIN_RCV_DATA_BUFFERS) &&
(adapter->AllRcvBlockCount < SXG_MAX_RCV_BLOCKS) &&
(adapter->AllocationsPending == 0)) {
@@ -3502,12 +3503,12 @@ static void sxg_stock_rcv_buffers(p_adapter_t adapter)
ReceiveBufferSize),
SXG_BUFFER_TYPE_RCV);
}
- // Now grab the RcvQLock lock and proceed
+ /* Now grab the RcvQLock lock and proceed */
spin_lock(&adapter->RcvQLock);
while (adapter->RcvBuffersOnCard < SXG_RCV_DATA_BUFFERS) {
PLIST_ENTRY _ple;
- // Get a descriptor block
+ /* Get a descriptor block */
RcvDescriptorBlockHdr = NULL;
if (adapter->FreeRcvBlockCount) {
_ple = RemoveHeadList(&adapter->FreeRcvBlocks);
@@ -3519,14 +3520,14 @@ static void sxg_stock_rcv_buffers(p_adapter_t adapter)
}
if (RcvDescriptorBlockHdr == NULL) {
- // Bail out..
+ /* Bail out.. */
adapter->Stats.NoMem++;
break;
}
- // Fill in the descriptor block and give it to the card
+ /* Fill in the descriptor block and give it to the card */
if (sxg_fill_descriptor_block(adapter, RcvDescriptorBlockHdr) ==
STATUS_FAILURE) {
- // Free the descriptor block
+ /* Free the descriptor block */
SXG_FREE_RCV_DESCRIPTOR_BLOCK(adapter,
RcvDescriptorBlockHdr);
break;
@@ -3560,15 +3561,15 @@ static void sxg_complete_descriptor_blocks(p_adapter_t adapter,
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpRBlks",
adapter, Index, RcvRingInfo->Head, RcvRingInfo->Tail);
- // Now grab the RcvQLock lock and proceed
+ /* Now grab the RcvQLock lock and proceed */
spin_lock(&adapter->RcvQLock);
ASSERT(Index != RcvRingInfo->Tail);
while (RcvRingInfo->Tail != Index) {
- //
- // Locate the current Cmd (ring descriptor entry), and
- // associated receive descriptor block, and advance
- // the tail
- //
+ /* */
+ /* Locate the current Cmd (ring descriptor entry), and */
+ /* associated receive descriptor block, and advance */
+ /* the tail */
+ /* */
SXG_RETURN_CMD(RingZero,
RcvRingInfo,
RingDescriptorCmd, RcvDescriptorBlockHdr);
@@ -3576,12 +3577,12 @@ static void sxg_complete_descriptor_blocks(p_adapter_t adapter,
RcvRingInfo->Head, RcvRingInfo->Tail,
RingDescriptorCmd, RcvDescriptorBlockHdr);
- // Clear the SGL field
+ /* Clear the SGL field */
RingDescriptorCmd->Sgl = 0;
- // Attempt to refill it and hand it right back to the
- // card. If we fail to refill it, free the descriptor block
- // header. The card will be restocked later via the
- // RcvBuffersOnCard test
+ /* Attempt to refill it and hand it right back to the */
+ /* card. If we fail to refill it, free the descriptor block */
+ /* header. The card will be restocked later via the */
+ /* RcvBuffersOnCard test */
if (sxg_fill_descriptor_block(adapter, RcvDescriptorBlockHdr) ==
STATUS_FAILURE) {
SXG_FREE_RCV_DESCRIPTOR_BLOCK(adapter,
diff --git a/drivers/staging/sxg/sxg_os.h b/drivers/staging/sxg/sxg_os.h
index 26fb0ffafa5..01182689aab 100644
--- a/drivers/staging/sxg/sxg_os.h
+++ b/drivers/staging/sxg/sxg_os.h
@@ -44,7 +44,6 @@
#define FALSE (0)
#define TRUE (1)
-
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *nle_flink;
struct _LIST_ENTRY *nle_blink;
@@ -69,35 +68,32 @@ typedef struct _LIST_ENTRY {
/* These two have to be inlined since they return things. */
-static __inline PLIST_ENTRY
-RemoveHeadList(list_entry *l)
+static __inline PLIST_ENTRY RemoveHeadList(list_entry * l)
{
- list_entry *f;
- list_entry *e;
+ list_entry *f;
+ list_entry *e;
- e = l->nle_flink;
- f = e->nle_flink;
- l->nle_flink = f;
- f->nle_blink = l;
+ e = l->nle_flink;
+ f = e->nle_flink;
+ l->nle_flink = f;
+ f->nle_blink = l;
- return (e);
+ return (e);
}
-static __inline PLIST_ENTRY
-RemoveTailList(list_entry *l)
+static __inline PLIST_ENTRY RemoveTailList(list_entry * l)
{
- list_entry *b;
- list_entry *e;
+ list_entry *b;
+ list_entry *e;
- e = l->nle_blink;
- b = e->nle_blink;
- l->nle_blink = b;
- b->nle_flink = l;
+ e = l->nle_blink;
+ b = e->nle_blink;
+ l->nle_blink = b;
+ b->nle_flink = l;
- return (e);
+ return (e);
}
-
#define InsertTailList(l, e) \
do { \
list_entry *b; \
@@ -120,7 +116,6 @@ RemoveTailList(list_entry *l)
(l)->nle_flink = (e); \
} while (0)
-
#define ATK_DEBUG 1
#if ATK_DEBUG
@@ -133,7 +128,6 @@ RemoveTailList(list_entry *l)
#define SLIC_TIMESTAMP(value)
#endif
-
/****************** SXG DEFINES *****************************************/
#ifdef ATKDBG
@@ -150,5 +144,4 @@ RemoveTailList(list_entry *l)
#define WRITE_REG64(a,reg,value,cpu) sxg_reg64_write((a),(&reg),(value),(cpu))
#define READ_REG(reg,value) (value) = readl((void __iomem *)(&reg))
-#endif /* _SLIC_OS_SPECIFIC_H_ */
-
+#endif /* _SLIC_OS_SPECIFIC_H_ */
diff --git a/drivers/staging/sxg/sxgdbg.h b/drivers/staging/sxg/sxgdbg.h
index cfb6c7c77a9..4522b8d7149 100644
--- a/drivers/staging/sxg/sxgdbg.h
+++ b/drivers/staging/sxg/sxgdbg.h
@@ -58,7 +58,7 @@
{ \
if (!(a)) { \
DBG_ERROR("ASSERT() Failure: file %s, function %s line %d\n",\
- __FILE__, __FUNCTION__, __LINE__); \
+ __FILE__, __func__, __LINE__); \
} \
}
#endif
diff --git a/drivers/staging/sxg/sxghif.h b/drivers/staging/sxg/sxghif.h
index ed26ceaa131..88bffbaa3be 100644
--- a/drivers/staging/sxg/sxghif.h
+++ b/drivers/staging/sxg/sxghif.h
@@ -14,119 +14,119 @@
*******************************************************************************/
typedef struct _SXG_UCODE_REGS {
// Address 0 - 0x3F = Command codes 0-15 for TCB 0. Excode 0
- u32 Icr; // Code = 0 (extended), ExCode = 0 - Int control
- u32 RsvdReg1; // Code = 1 - TOE -NA
- u32 RsvdReg2; // Code = 2 - TOE -NA
- u32 RsvdReg3; // Code = 3 - TOE -NA
- u32 RsvdReg4; // Code = 4 - TOE -NA
- u32 RsvdReg5; // Code = 5 - TOE -NA
- u32 CardUp; // Code = 6 - Microcode initialized when 1
- u32 RsvdReg7; // Code = 7 - TOE -NA
- u32 CodeNotUsed[8]; // Codes 8-15 not used. ExCode = 0
+ u32 Icr; // Code = 0 (extended), ExCode = 0 - Int control
+ u32 RsvdReg1; // Code = 1 - TOE -NA
+ u32 RsvdReg2; // Code = 2 - TOE -NA
+ u32 RsvdReg3; // Code = 3 - TOE -NA
+ u32 RsvdReg4; // Code = 4 - TOE -NA
+ u32 RsvdReg5; // Code = 5 - TOE -NA
+ u32 CardUp; // Code = 6 - Microcode initialized when 1
+ u32 RsvdReg7; // Code = 7 - TOE -NA
+ u32 CodeNotUsed[8]; // Codes 8-15 not used. ExCode = 0
// This brings us to ExCode 1 at address 0x40 = Interrupt status pointer
- u32 Isp; // Code = 0 (extended), ExCode = 1
- u32 PadEx1[15]; // Codes 1-15 not used with extended codes
+ u32 Isp; // Code = 0 (extended), ExCode = 1
+ u32 PadEx1[15]; // Codes 1-15 not used with extended codes
// ExCode 2 = Interrupt Status Register
- u32 Isr; // Code = 0 (extended), ExCode = 2
- u32 PadEx2[15];
+ u32 Isr; // Code = 0 (extended), ExCode = 2
+ u32 PadEx2[15];
// ExCode 3 = Event base register. Location of event rings
- u32 EventBase; // Code = 0 (extended), ExCode = 3
- u32 PadEx3[15];
+ u32 EventBase; // Code = 0 (extended), ExCode = 3
+ u32 PadEx3[15];
// ExCode 4 = Event ring size
- u32 EventSize; // Code = 0 (extended), ExCode = 4
- u32 PadEx4[15];
+ u32 EventSize; // Code = 0 (extended), ExCode = 4
+ u32 PadEx4[15];
// ExCode 5 = TCB Buffers base address
- u32 TcbBase; // Code = 0 (extended), ExCode = 5
- u32 PadEx5[15];
+ u32 TcbBase; // Code = 0 (extended), ExCode = 5
+ u32 PadEx5[15];
// ExCode 6 = TCB Composite Buffers base address
- u32 TcbCompBase; // Code = 0 (extended), ExCode = 6
- u32 PadEx6[15];
+ u32 TcbCompBase; // Code = 0 (extended), ExCode = 6
+ u32 PadEx6[15];
// ExCode 7 = Transmit ring base address
- u32 XmtBase; // Code = 0 (extended), ExCode = 7
- u32 PadEx7[15];
+ u32 XmtBase; // Code = 0 (extended), ExCode = 7
+ u32 PadEx7[15];
// ExCode 8 = Transmit ring size
- u32 XmtSize; // Code = 0 (extended), ExCode = 8
- u32 PadEx8[15];
+ u32 XmtSize; // Code = 0 (extended), ExCode = 8
+ u32 PadEx8[15];
// ExCode 9 = Receive ring base address
- u32 RcvBase; // Code = 0 (extended), ExCode = 9
- u32 PadEx9[15];
+ u32 RcvBase; // Code = 0 (extended), ExCode = 9
+ u32 PadEx9[15];
// ExCode 10 = Receive ring size
- u32 RcvSize; // Code = 0 (extended), ExCode = 10
- u32 PadEx10[15];
+ u32 RcvSize; // Code = 0 (extended), ExCode = 10
+ u32 PadEx10[15];
// ExCode 11 = Read EEPROM Config
- u32 Config; // Code = 0 (extended), ExCode = 11
- u32 PadEx11[15];
+ u32 Config; // Code = 0 (extended), ExCode = 11
+ u32 PadEx11[15];
// ExCode 12 = Multicast bits 31:0
- u32 McastLow; // Code = 0 (extended), ExCode = 12
- u32 PadEx12[15];
+ u32 McastLow; // Code = 0 (extended), ExCode = 12
+ u32 PadEx12[15];
// ExCode 13 = Multicast bits 63:32
- u32 McastHigh; // Code = 0 (extended), ExCode = 13
- u32 PadEx13[15];
+ u32 McastHigh; // Code = 0 (extended), ExCode = 13
+ u32 PadEx13[15];
// ExCode 14 = Ping
- u32 Ping; // Code = 0 (extended), ExCode = 14
- u32 PadEx14[15];
+ u32 Ping; // Code = 0 (extended), ExCode = 14
+ u32 PadEx14[15];
// ExCode 15 = Link MTU
- u32 LinkMtu; // Code = 0 (extended), ExCode = 15
- u32 PadEx15[15];
+ u32 LinkMtu; // Code = 0 (extended), ExCode = 15
+ u32 PadEx15[15];
// ExCode 16 = Download synchronization
- u32 LoadSync; // Code = 0 (extended), ExCode = 16
- u32 PadEx16[15];
+ u32 LoadSync; // Code = 0 (extended), ExCode = 16
+ u32 PadEx16[15];
// ExCode 17 = Upper DRAM address bits on 32-bit systems
- u32 Upper; // Code = 0 (extended), ExCode = 17
- u32 PadEx17[15];
+ u32 Upper; // Code = 0 (extended), ExCode = 17
+ u32 PadEx17[15];
// ExCode 18 = Slowpath Send Index Address
- u32 SPSendIndex; // Code = 0 (extended), ExCode = 18
- u32 PadEx18[15];
- u32 RsvdXF; // Code = 0 (extended), ExCode = 19
- u32 PadEx19[15];
+ u32 SPSendIndex; // Code = 0 (extended), ExCode = 18
+ u32 PadEx18[15];
+ u32 RsvdXF; // Code = 0 (extended), ExCode = 19
+ u32 PadEx19[15];
// ExCode 20 = Aggregation
- u32 Aggregation; // Code = 0 (extended), ExCode = 20
- u32 PadEx20[15];
+ u32 Aggregation; // Code = 0 (extended), ExCode = 20
+ u32 PadEx20[15];
// ExCode 21 = Receive MDL push timer
- u32 PushTicks; // Code = 0 (extended), ExCode = 21
- u32 PadEx21[15];
+ u32 PushTicks; // Code = 0 (extended), ExCode = 21
+ u32 PadEx21[15];
// ExCode 22 = TOE NA
- u32 AckFrequency; // Code = 0 (extended), ExCode = 22
- u32 PadEx22[15];
+ u32 AckFrequency; // Code = 0 (extended), ExCode = 22
+ u32 PadEx22[15];
// ExCode 23 = TOE NA
- u32 RsvdReg23;
- u32 PadEx23[15];
+ u32 RsvdReg23;
+ u32 PadEx23[15];
// ExCode 24 = TOE NA
- u32 RsvdReg24;
- u32 PadEx24[15];
+ u32 RsvdReg24;
+ u32 PadEx24[15];
// ExCode 25 = TOE NA
- u32 RsvdReg25; // Code = 0 (extended), ExCode = 25
- u32 PadEx25[15];
+ u32 RsvdReg25; // Code = 0 (extended), ExCode = 25
+ u32 PadEx25[15];
// ExCode 26 = Receive checksum requirements
- u32 ReceiveChecksum; // Code = 0 (extended), ExCode = 26
- u32 PadEx26[15];
+ u32 ReceiveChecksum; // Code = 0 (extended), ExCode = 26
+ u32 PadEx26[15];
// ExCode 27 = RSS Requirements
- u32 Rss; // Code = 0 (extended), ExCode = 27
- u32 PadEx27[15];
+ u32 Rss; // Code = 0 (extended), ExCode = 27
+ u32 PadEx27[15];
// ExCode 28 = RSS Table
- u32 RssTable; // Code = 0 (extended), ExCode = 28
- u32 PadEx28[15];
+ u32 RssTable; // Code = 0 (extended), ExCode = 28
+ u32 PadEx28[15];
// ExCode 29 = Event ring release entries
- u32 EventRelease; // Code = 0 (extended), ExCode = 29
- u32 PadEx29[15];
+ u32 EventRelease; // Code = 0 (extended), ExCode = 29
+ u32 PadEx29[15];
// ExCode 30 = Number of receive bufferlist commands on ring 0
- u32 RcvCmd; // Code = 0 (extended), ExCode = 30
- u32 PadEx30[15];
+ u32 RcvCmd; // Code = 0 (extended), ExCode = 30
+ u32 PadEx30[15];
// ExCode 31 = slowpath transmit command - Data[31:0] = 1
- u32 XmtCmd; // Code = 0 (extended), ExCode = 31
- u32 PadEx31[15];
+ u32 XmtCmd; // Code = 0 (extended), ExCode = 31
+ u32 PadEx31[15];
// ExCode 32 = Dump command
- u32 DumpCmd; // Code = 0 (extended), ExCode = 32
- u32 PadEx32[15];
+ u32 DumpCmd; // Code = 0 (extended), ExCode = 32
+ u32 PadEx32[15];
// ExCode 33 = Debug command
- u32 DebugCmd; // Code = 0 (extended), ExCode = 33
- u32 PadEx33[15];
+ u32 DebugCmd; // Code = 0 (extended), ExCode = 33
+ u32 PadEx33[15];
// There are 128 possible extended commands - each of account for 16
// words (including the non-relevent base command codes 1-15).
// Pad for the remainder of these here to bring us to the next CPU
// base. As extended codes are added, reduce the first array value in
// the following field
- u32 PadToNextCpu[94][16]; // 94 = 128 - 34 (34 = Excodes 0 - 33)
+ u32 PadToNextCpu[94][16]; // 94 = 128 - 34 (34 = Excodes 0 - 33)
} SXG_UCODE_REGS, *PSXG_UCODE_REGS;
// Interrupt control register (0) values
@@ -141,7 +141,7 @@ typedef struct _SXG_UCODE_REGS {
// The Microcode supports up to 16 RSS queues
#define SXG_MAX_RSS 16
-#define SXG_MAX_RSS_TABLE_SIZE 256 // 256-byte max
+#define SXG_MAX_RSS_TABLE_SIZE 256 // 256-byte max
#define SXG_RSS_TCP6 0x00000001 // RSS TCP over IPv6
#define SXG_RSS_TCP4 0x00000002 // RSS TCP over IPv4
@@ -170,16 +170,16 @@ typedef struct _SXG_UCODE_REGS {
* SXG_UCODE_REGS definition above
*/
typedef struct _SXG_TCB_REGS {
- u32 ExCode; /* Extended codes - see SXG_UCODE_REGS */
- u32 Xmt; /* Code = 1 - # of Xmt descriptors added to ring */
- u32 Rcv; /* Code = 2 - # of Rcv descriptors added to ring */
- u32 Rsvd1; /* Code = 3 - TOE NA */
- u32 Rsvd2; /* Code = 4 - TOE NA */
- u32 Rsvd3; /* Code = 5 - TOE NA */
- u32 Invalid; /* Code = 6 - Reserved for "CardUp" see above */
- u32 Rsvd4; /* Code = 7 - TOE NA */
- u32 Rsvd5; /* Code = 8 - TOE NA */
- u32 Pad[7]; /* Codes 8-15 - Not used. */
+ u32 ExCode; /* Extended codes - see SXG_UCODE_REGS */
+ u32 Xmt; /* Code = 1 - # of Xmt descriptors added to ring */
+ u32 Rcv; /* Code = 2 - # of Rcv descriptors added to ring */
+ u32 Rsvd1; /* Code = 3 - TOE NA */
+ u32 Rsvd2; /* Code = 4 - TOE NA */
+ u32 Rsvd3; /* Code = 5 - TOE NA */
+ u32 Invalid; /* Code = 6 - Reserved for "CardUp" see above */
+ u32 Rsvd4; /* Code = 7 - TOE NA */
+ u32 Rsvd5; /* Code = 8 - TOE NA */
+ u32 Pad[7]; /* Codes 8-15 - Not used. */
} SXG_TCB_REGS, *PSXG_TCB_REGS;
/***************************************************************************
@@ -273,27 +273,27 @@ typedef struct _SXG_TCB_REGS {
*/
#pragma pack(push, 1)
typedef struct _SXG_EVENT {
- u32 Pad[1]; // not used
- u32 SndUna; // SndUna value
- u32 Resid; // receive MDL resid
+ u32 Pad[1]; // not used
+ u32 SndUna; // SndUna value
+ u32 Resid; // receive MDL resid
union {
- void * HostHandle; // Receive host handle
- u32 Rsvd1; // TOE NA
+ void *HostHandle; // Receive host handle
+ u32 Rsvd1; // TOE NA
struct {
- u32 NotUsed;
- u32 Rsvd2; // TOE NA
+ u32 NotUsed;
+ u32 Rsvd2; // TOE NA
} Flush;
};
- u32 Toeplitz; // RSS Toeplitz hash
+ u32 Toeplitz; // RSS Toeplitz hash
union {
- ushort Rsvd3; // TOE NA
- ushort HdrOffset; // Slowpath
+ ushort Rsvd3; // TOE NA
+ ushort HdrOffset; // Slowpath
};
- ushort Length; //
- unsigned char Rsvd4; // TOE NA
- unsigned char Code; // Event code
- unsigned char CommandIndex; // New ring index
- unsigned char Status; // Event status
+ ushort Length; //
+ unsigned char Rsvd4; // TOE NA
+ unsigned char Code; // Event code
+ unsigned char CommandIndex; // New ring index
+ unsigned char Status; // Event status
} SXG_EVENT, *PSXG_EVENT;
#pragma pack(pop)
@@ -318,12 +318,12 @@ typedef struct _SXG_EVENT {
// Event ring
// Size must be power of 2, between 128 and 16k
#define EVENT_RING_SIZE 4096 // ??
-#define EVENT_RING_BATCH 16 // Hand entries back 16 at a time.
-#define EVENT_BATCH_LIMIT 256 // Stop processing events after 256 (16 * 16)
+#define EVENT_RING_BATCH 16 // Hand entries back 16 at a time.
+#define EVENT_BATCH_LIMIT 256 // Stop processing events after 256 (16 * 16)
typedef struct _SXG_EVENT_RING {
- SXG_EVENT Ring[EVENT_RING_SIZE];
-}SXG_EVENT_RING, *PSXG_EVENT_RING;
+ SXG_EVENT Ring[EVENT_RING_SIZE];
+} SXG_EVENT_RING, *PSXG_EVENT_RING;
/***************************************************************************
*
@@ -341,7 +341,7 @@ typedef struct _SXG_EVENT_RING {
#define SXG_TCB_PER_BUCKET 16
#define SXG_TCB_BUCKET_MASK 0xFF0 // Bucket portion of TCB ID
#define SXG_TCB_ELEMENT_MASK 0x00F // Element within bucket
-#define SXG_TCB_BUCKETS 256 // 256 * 16 = 4k
+#define SXG_TCB_BUCKETS 256 // 256 * 16 = 4k
#define SXG_TCB_BUFFER_SIZE 512 // ASSERT format is correct
@@ -368,7 +368,6 @@ typedef struct _SXG_EVENT_RING {
&(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp6.Ip : \
&(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp6.Ip
-
#if DBG
// Horrible kludge to distinguish dumb-nic, slowpath, and
// fastpath traffic. Decrement the HopLimit by one
@@ -396,16 +395,16 @@ typedef struct _SXG_EVENT_RING {
* Receive and transmit rings
***************************************************************************/
#define SXG_MAX_RING_SIZE 256
-#define SXG_XMT_RING_SIZE 128 // Start with 128
-#define SXG_RCV_RING_SIZE 128 // Start with 128
+#define SXG_XMT_RING_SIZE 128 // Start with 128
+#define SXG_RCV_RING_SIZE 128 // Start with 128
#define SXG_MAX_ENTRIES 4096
// Structure and macros to manage a ring
typedef struct _SXG_RING_INFO {
- unsigned char Head; // Where we add entries - Note unsigned char:RING_SIZE
- unsigned char Tail; // Where we pull off completed entries
- ushort Size; // Ring size - Must be multiple of 2
- void * Context[SXG_MAX_RING_SIZE]; // Shadow ring
+ unsigned char Head; // Where we add entries - Note unsigned char:RING_SIZE
+ unsigned char Tail; // Where we pull off completed entries
+ ushort Size; // Ring size - Must be multiple of 2
+ void *Context[SXG_MAX_RING_SIZE]; // Shadow ring
} SXG_RING_INFO, *PSXG_RING_INFO;
#define SXG_INITIALIZE_RING(_ring, _size) { \
@@ -483,40 +482,40 @@ typedef struct _SXG_RING_INFO {
*/
#pragma pack(push, 1)
typedef struct _SXG_CMD {
- dma_addr_t Sgl; // Physical address of SGL
+ dma_addr_t Sgl; // Physical address of SGL
union {
struct {
- dma64_addr_t FirstSgeAddress;// Address of first SGE
- u32 FirstSgeLength; // Length of first SGE
+ dma64_addr_t FirstSgeAddress; // Address of first SGE
+ u32 FirstSgeLength; // Length of first SGE
union {
- u32 Rsvd1; // TOE NA
- u32 SgeOffset; // Slowpath - 2nd SGE offset
- u32 Resid; // MDL completion - clobbers update
+ u32 Rsvd1; // TOE NA
+ u32 SgeOffset; // Slowpath - 2nd SGE offset
+ u32 Resid; // MDL completion - clobbers update
};
union {
- u32 TotalLength; // Total transfer length
- u32 Mss; // LSO MSS
+ u32 TotalLength; // Total transfer length
+ u32 Mss; // LSO MSS
};
} Buffer;
};
union {
struct {
- unsigned char Flags:4; // slowpath flags
- unsigned char IpHl:4; // Ip header length (>>2)
- unsigned char MacLen; // Mac header len
+ unsigned char Flags:4; // slowpath flags
+ unsigned char IpHl:4; // Ip header length (>>2)
+ unsigned char MacLen; // Mac header len
} CsumFlags;
struct {
- ushort Flags:4; // slowpath flags
- ushort TcpHdrOff:7; // TCP
- ushort MacLen:5; // Mac header len
+ ushort Flags:4; // slowpath flags
+ ushort TcpHdrOff:7; // TCP
+ ushort MacLen:5; // Mac header len
} LsoFlags;
- ushort Flags; // flags
+ ushort Flags; // flags
};
union {
- ushort SgEntries; // SG entry count including first sge
+ ushort SgEntries; // SG entry count including first sge
struct {
- unsigned char Status; // Copied from event status
- unsigned char NotUsed;
+ unsigned char Status; // Copied from event status
+ unsigned char NotUsed;
} Status;
};
} SXG_CMD, *PSXG_CMD;
@@ -524,8 +523,8 @@ typedef struct _SXG_CMD {
#pragma pack(push, 1)
typedef struct _VLAN_HDR {
- ushort VlanTci;
- ushort VlanTpid;
+ ushort VlanTci;
+ ushort VlanTpid;
} VLAN_HDR, *PVLAN_HDR;
#pragma pack(pop)
@@ -561,16 +560,16 @@ typedef struct _VLAN_HDR {
*
*/
// Slowpath CMD flags
-#define SXG_SLOWCMD_CSUM_IP 0x01 // Checksum IP
-#define SXG_SLOWCMD_CSUM_TCP 0x02 // Checksum TCP
-#define SXG_SLOWCMD_LSO 0x04 // Large segment send
+#define SXG_SLOWCMD_CSUM_IP 0x01 // Checksum IP
+#define SXG_SLOWCMD_CSUM_TCP 0x02 // Checksum TCP
+#define SXG_SLOWCMD_LSO 0x04 // Large segment send
typedef struct _SXG_XMT_RING {
- SXG_CMD Descriptors[SXG_XMT_RING_SIZE];
+ SXG_CMD Descriptors[SXG_XMT_RING_SIZE];
} SXG_XMT_RING, *PSXG_XMT_RING;
typedef struct _SXG_RCV_RING {
- SXG_CMD Descriptors[SXG_RCV_RING_SIZE];
+ SXG_CMD Descriptors[SXG_RCV_RING_SIZE];
} SXG_RCV_RING, *PSXG_RCV_RING;
/***************************************************************************
@@ -578,8 +577,8 @@ typedef struct _SXG_RCV_RING {
* shared memory allocation
***************************************************************************/
typedef enum {
- SXG_BUFFER_TYPE_RCV, // Receive buffer
- SXG_BUFFER_TYPE_SGL // SGL buffer
+ SXG_BUFFER_TYPE_RCV, // Receive buffer
+ SXG_BUFFER_TYPE_SGL // SGL buffer
} SXG_BUFFER_TYPE;
// State for SXG buffers
@@ -668,60 +667,60 @@ typedef enum {
#define SXG_RCV_DATA_BUFFERS 4096 // Amount to give to the card
#define SXG_INITIAL_RCV_DATA_BUFFERS 8192 // Initial pool of buffers
#define SXG_MIN_RCV_DATA_BUFFERS 2048 // Minimum amount and when to get more
-#define SXG_MAX_RCV_BLOCKS 128 // = 16384 receive buffers
+#define SXG_MAX_RCV_BLOCKS 128 // = 16384 receive buffers
// Receive buffer header
typedef struct _SXG_RCV_DATA_BUFFER_HDR {
- dma_addr_t PhysicalAddress; // Buffer physical address
+ dma_addr_t PhysicalAddress; // Buffer physical address
// Note - DO NOT USE the VirtualAddress field to locate data.
// Use the sxg.h:SXG_RECEIVE_DATA_LOCATION macro instead.
- void *VirtualAddress; // Start of buffer
- LIST_ENTRY FreeList; // Free queue of buffers
- struct _SXG_RCV_DATA_BUFFER_HDR *Next; // Fastpath data buffer queue
- u32 Size; // Buffer size
- u32 ByteOffset; // See SXG_RESTORE_MDL_OFFSET
- unsigned char State; // See SXG_BUFFER state above
- unsigned char Status; // Event status (to log PUSH)
- struct sk_buff * skb; // Double mapped (nbl and pkt)
+ void *VirtualAddress; // Start of buffer
+ LIST_ENTRY FreeList; // Free queue of buffers
+ struct _SXG_RCV_DATA_BUFFER_HDR *Next; // Fastpath data buffer queue
+ u32 Size; // Buffer size
+ u32 ByteOffset; // See SXG_RESTORE_MDL_OFFSET
+ unsigned char State; // See SXG_BUFFER state above
+ unsigned char Status; // Event status (to log PUSH)
+ struct sk_buff *skb; // Double mapped (nbl and pkt)
} SXG_RCV_DATA_BUFFER_HDR, *PSXG_RCV_DATA_BUFFER_HDR;
// SxgSlowReceive uses the PACKET (skb) contained
// in the SXG_RCV_DATA_BUFFER_HDR when indicating dumb-nic data
#define SxgDumbRcvPacket skb
-#define SXG_RCV_DATA_HDR_SIZE 256 // Space for SXG_RCV_DATA_BUFFER_HDR
+#define SXG_RCV_DATA_HDR_SIZE 256 // Space for SXG_RCV_DATA_BUFFER_HDR
#define SXG_RCV_DATA_BUFFER_SIZE 2048 // Non jumbo = 2k including HDR
#define SXG_RCV_JUMBO_BUFFER_SIZE 10240 // jumbo = 10k including HDR
// Receive data descriptor
typedef struct _SXG_RCV_DATA_DESCRIPTOR {
union {
- struct sk_buff * VirtualAddress; // Host handle
- u64 ForceTo8Bytes; // Force x86 to 8-byte boundary
+ struct sk_buff *VirtualAddress; // Host handle
+ u64 ForceTo8Bytes; // Force x86 to 8-byte boundary
};
- dma_addr_t PhysicalAddress;
+ dma_addr_t PhysicalAddress;
} SXG_RCV_DATA_DESCRIPTOR, *PSXG_RCV_DATA_DESCRIPTOR;
// Receive descriptor block
#define SXG_RCV_DESCRIPTORS_PER_BLOCK 128
#define SXG_RCV_DESCRIPTOR_BLOCK_SIZE 2048 // For sanity check
typedef struct _SXG_RCV_DESCRIPTOR_BLOCK {
- SXG_RCV_DATA_DESCRIPTOR Descriptors[SXG_RCV_DESCRIPTORS_PER_BLOCK];
+ SXG_RCV_DATA_DESCRIPTOR Descriptors[SXG_RCV_DESCRIPTORS_PER_BLOCK];
} SXG_RCV_DESCRIPTOR_BLOCK, *PSXG_RCV_DESCRIPTOR_BLOCK;
// Receive descriptor block header
typedef struct _SXG_RCV_DESCRIPTOR_BLOCK_HDR {
- void * VirtualAddress; // Start of 2k buffer
- dma_addr_t PhysicalAddress; // ..and it's physical address
- LIST_ENTRY FreeList; // Free queue of descriptor blocks
- unsigned char State; // See SXG_BUFFER state above
+ void *VirtualAddress; // Start of 2k buffer
+ dma_addr_t PhysicalAddress; // ..and it's physical address
+ LIST_ENTRY FreeList; // Free queue of descriptor blocks
+ unsigned char State; // See SXG_BUFFER state above
} SXG_RCV_DESCRIPTOR_BLOCK_HDR, *PSXG_RCV_DESCRIPTOR_BLOCK_HDR;
// Receive block header
typedef struct _SXG_RCV_BLOCK_HDR {
- void * VirtualAddress; // Start of virtual memory
- dma_addr_t PhysicalAddress; // ..and it's physical address
- LIST_ENTRY AllList; // Queue of all SXG_RCV_BLOCKS
+ void *VirtualAddress; // Start of virtual memory
+ dma_addr_t PhysicalAddress; // ..and it's physical address
+ LIST_ENTRY AllList; // Queue of all SXG_RCV_BLOCKS
} SXG_RCV_BLOCK_HDR, *PSXG_RCV_BLOCK_HDR;
// Macros to determine data structure offsets into receive block
@@ -747,8 +746,8 @@ typedef struct _SXG_RCV_BLOCK_HDR {
// Use the miniport reserved portion of the NBL to locate
// our SXG_RCV_DATA_BUFFER_HDR structure.
typedef struct _SXG_RCV_NBL_RESERVED {
- PSXG_RCV_DATA_BUFFER_HDR RcvDataBufferHdr;
- void * Available;
+ PSXG_RCV_DATA_BUFFER_HDR RcvDataBufferHdr;
+ void *Available;
} SXG_RCV_NBL_RESERVED, *PSXG_RCV_NBL_RESERVED;
#define SXG_RCV_NBL_BUFFER_HDR(_NBL) (((PSXG_RCV_NBL_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(_NBL))->RcvDataBufferHdr)
@@ -760,12 +759,11 @@ typedef struct _SXG_RCV_NBL_RESERVED {
#define SXG_MIN_SGL_BUFFERS 2048 // Minimum amount and when to get more
#define SXG_MAX_SGL_BUFFERS 16384 // Maximum to allocate (note ADAPT:ushort)
-
// Self identifying structure type
typedef enum _SXG_SGL_TYPE {
- SXG_SGL_DUMB, // Dumb NIC SGL
- SXG_SGL_SLOW, // Slowpath protocol header - see below
- SXG_SGL_CHIMNEY // Chimney offload SGL
+ SXG_SGL_DUMB, // Dumb NIC SGL
+ SXG_SGL_SLOW, // Slowpath protocol header - see below
+ SXG_SGL_CHIMNEY // Chimney offload SGL
} SXG_SGL_TYPE, PSXG_SGL_TYPE;
// Note - the description below is Microsoft specific
@@ -774,14 +772,14 @@ typedef enum _SXG_SGL_TYPE {
// for the SCATTER_GATHER_LIST portion of the SXG_SCATTER_GATHER data structure.
// The following considerations apply when setting this value:
// - First, the Sahara card is designed to read the Microsoft SGL structure
-// straight out of host memory. This means that the SGL must reside in
-// shared memory. If the length here is smaller than the SGL for the
-// NET_BUFFER, then NDIS will allocate its own buffer. The buffer
-// that NDIS allocates is not in shared memory, so when this happens,
-// the SGL will need to be copied to a set of SXG_SCATTER_GATHER buffers.
-// In other words.. we don't want this value to be too small.
+// straight out of host memory. This means that the SGL must reside in
+// shared memory. If the length here is smaller than the SGL for the
+// NET_BUFFER, then NDIS will allocate its own buffer. The buffer
+// that NDIS allocates is not in shared memory, so when this happens,
+// the SGL will need to be copied to a set of SXG_SCATTER_GATHER buffers.
+// In other words.. we don't want this value to be too small.
// - On the other hand.. we're allocating up to 16k of these things. If
-// we make this too big, we start to consume a ton of memory..
+// we make this too big, we start to consume a ton of memory..
// At the moment, I'm going to limit the number of SG entries to 150.
// If each entry maps roughly 4k, then this should cover roughly 600kB
// NET_BUFFERs. Furthermore, since each entry is 24 bytes, the total
@@ -801,24 +799,23 @@ typedef enum _SXG_SGL_TYPE {
// the SGL. The following structure defines an x64
// formatted SGL entry
typedef struct _SXG_X64_SGE {
- dma64_addr_t Address; // same as wdm.h
- u32 Length; // same as wdm.h
- u32 CompilerPad;// The compiler pads to 8-bytes
- u64 Reserved; // u32 * in wdm.h. Force to 8 bytes
+ dma64_addr_t Address; // same as wdm.h
+ u32 Length; // same as wdm.h
+ u32 CompilerPad; // The compiler pads to 8-bytes
+ u64 Reserved; // u32 * in wdm.h. Force to 8 bytes
} SXG_X64_SGE, *PSXG_X64_SGE;
typedef struct _SCATTER_GATHER_ELEMENT {
- dma64_addr_t Address; // same as wdm.h
- u32 Length; // same as wdm.h
- u32 CompilerPad;// The compiler pads to 8-bytes
- u64 Reserved; // u32 * in wdm.h. Force to 8 bytes
+ dma64_addr_t Address; // same as wdm.h
+ u32 Length; // same as wdm.h
+ u32 CompilerPad; // The compiler pads to 8-bytes
+ u64 Reserved; // u32 * in wdm.h. Force to 8 bytes
} SCATTER_GATHER_ELEMENT, *PSCATTER_GATHER_ELEMENT;
-
typedef struct _SCATTER_GATHER_LIST {
- u32 NumberOfElements;
- u32 * Reserved;
- SCATTER_GATHER_ELEMENT Elements[];
+ u32 NumberOfElements;
+ u32 *Reserved;
+ SCATTER_GATHER_ELEMENT Elements[];
} SCATTER_GATHER_LIST, *PSCATTER_GATHER_LIST;
// The card doesn't care about anything except elements, so
@@ -826,26 +823,26 @@ typedef struct _SCATTER_GATHER_LIST {
// SGL structure. But redefine from wdm.h:SCATTER_GATHER_LIST so
// we can specify SXG_X64_SGE and define a fixed number of elements
typedef struct _SXG_X64_SGL {
- u32 NumberOfElements;
- u32 * Reserved;
- SXG_X64_SGE Elements[SXG_SGL_ENTRIES];
+ u32 NumberOfElements;
+ u32 *Reserved;
+ SXG_X64_SGE Elements[SXG_SGL_ENTRIES];
} SXG_X64_SGL, *PSXG_X64_SGL;
typedef struct _SXG_SCATTER_GATHER {
- SXG_SGL_TYPE Type; // FIRST! Dumb-nic or offload
- void * adapter; // Back pointer to adapter
- LIST_ENTRY FreeList; // Free SXG_SCATTER_GATHER blocks
- LIST_ENTRY AllList; // All SXG_SCATTER_GATHER blocks
- dma_addr_t PhysicalAddress;// physical address
- unsigned char State; // See SXG_BUFFER state above
- unsigned char CmdIndex; // Command ring index
- struct sk_buff * DumbPacket; // Associated Packet
- u32 Direction; // For asynchronous completions
- u32 CurOffset; // Current SGL offset
- u32 SglRef; // SGL reference count
- VLAN_HDR VlanTag; // VLAN tag to be inserted into SGL
- PSCATTER_GATHER_LIST pSgl; // SGL Addr. Possibly &Sgl
- SXG_X64_SGL Sgl; // SGL handed to card
+ SXG_SGL_TYPE Type; // FIRST! Dumb-nic or offload
+ void *adapter; // Back pointer to adapter
+ LIST_ENTRY FreeList; // Free SXG_SCATTER_GATHER blocks
+ LIST_ENTRY AllList; // All SXG_SCATTER_GATHER blocks
+ dma_addr_t PhysicalAddress; // physical address
+ unsigned char State; // See SXG_BUFFER state above
+ unsigned char CmdIndex; // Command ring index
+ struct sk_buff *DumbPacket; // Associated Packet
+ u32 Direction; // For asynchronous completions
+ u32 CurOffset; // Current SGL offset
+ u32 SglRef; // SGL reference count
+ VLAN_HDR VlanTag; // VLAN tag to be inserted into SGL
+ PSCATTER_GATHER_LIST pSgl; // SGL Addr. Possibly &Sgl
+ SXG_X64_SGL Sgl; // SGL handed to card
} SXG_SCATTER_GATHER, *PSXG_SCATTER_GATHER;
#if defined(CONFIG_X86_64)
@@ -856,6 +853,5 @@ typedef struct _SXG_SCATTER_GATHER {
#define SXG_SGL_BUFFER(_SxgSgl) NULL
#define SXG_SGL_BUF_SIZE 0
#else
- Stop Compilation;
+Stop Compilation;
#endif
-
diff --git a/drivers/staging/sxg/sxghw.h b/drivers/staging/sxg/sxghw.h
index 8f4f6effdd9..2222ae91fd9 100644
--- a/drivers/staging/sxg/sxghw.h
+++ b/drivers/staging/sxg/sxghw.h
@@ -13,11 +13,11 @@
/*******************************************************************************
* Configuration space
*******************************************************************************/
-// PCI Vendor ID
-#define SXG_VENDOR_ID 0x139A // Alacritech's Vendor ID
+/* PCI Vendor ID */
+#define SXG_VENDOR_ID 0x139A /* Alacritech's Vendor ID */
// PCI Device ID
-#define SXG_DEVICE_ID 0x0009 // Sahara Device ID
+#define SXG_DEVICE_ID 0x0009 /* Sahara Device ID */
//
// Subsystem IDs.
@@ -141,7 +141,7 @@ typedef struct _SXG_HW_REGS {
#define SXG_REGISTER_SIZE_PER_CPU 0x00002000 // Used to sanity check UCODE_REGS structure
// Sahara receive sequencer status values
-#define SXG_RCV_STATUS_ATTN 0x80000000 // Attention
+#define SXG_RCV_STATUS_ATTN 0x80000000 // Attention
#define SXG_RCV_STATUS_TRANSPORT_MASK 0x3F000000 // Transport mask
#define SXG_RCV_STATUS_TRANSPORT_ERROR 0x20000000 // Transport error
#define SXG_RCV_STATUS_TRANSPORT_CSUM 0x23000000 // Transport cksum error
@@ -156,9 +156,9 @@ typedef struct _SXG_HW_REGS {
#define SXG_RCV_STATUS_TRANSPORT_FTP 0x03000000 // Transport FTP
#define SXG_RCV_STATUS_TRANSPORT_HTTP 0x02000000 // Transport HTTP
#define SXG_RCV_STATUS_TRANSPORT_SMB 0x01000000 // Transport SMB
-#define SXG_RCV_STATUS_NETWORK_MASK 0x00FF0000 // Network mask
+#define SXG_RCV_STATUS_NETWORK_MASK 0x00FF0000 // Network mask
#define SXG_RCV_STATUS_NETWORK_ERROR 0x00800000 // Network error
-#define SXG_RCV_STATUS_NETWORK_CSUM 0x00830000 // Network cksum error
+#define SXG_RCV_STATUS_NETWORK_CSUM 0x00830000 // Network cksum error
#define SXG_RCV_STATUS_NETWORK_UFLOW 0x00820000 // Network underflow error
#define SXG_RCV_STATUS_NETWORK_HDRLEN 0x00800000 // Network header length
#define SXG_RCV_STATUS_NETWORK_OFLOW 0x00400000 // Network overflow detected
@@ -167,67 +167,67 @@ typedef struct _SXG_HW_REGS {
#define SXG_RCV_STATUS_NETWORK_OFFSET 0x00080000 // Network offset detected
#define SXG_RCV_STATUS_NETWORK_FRAGMENT 0x00040000 // Network fragment detected
#define SXG_RCV_STATUS_NETWORK_TRANS_MASK 0x00030000 // Network transport type mask
-#define SXG_RCV_STATUS_NETWORK_UDP 0x00020000 // UDP
-#define SXG_RCV_STATUS_NETWORK_TCP 0x00010000 // TCP
-#define SXG_RCV_STATUS_IPONLY 0x00008000 // IP-only not TCP
-#define SXG_RCV_STATUS_PKT_PRI 0x00006000 // Receive priority
-#define SXG_RCV_STATUS_PKT_PRI_SHFT 13 // Receive priority shift
-#define SXG_RCV_STATUS_PARITY 0x00001000 // MAC Receive RAM parity error
-#define SXG_RCV_STATUS_ADDRESS_MASK 0x00000F00 // Link address detection mask
-#define SXG_RCV_STATUS_ADDRESS_D 0x00000B00 // Link address D
-#define SXG_RCV_STATUS_ADDRESS_C 0x00000A00 // Link address C
-#define SXG_RCV_STATUS_ADDRESS_B 0x00000900 // Link address B
-#define SXG_RCV_STATUS_ADDRESS_A 0x00000800 // Link address A
+#define SXG_RCV_STATUS_NETWORK_UDP 0x00020000 // UDP
+#define SXG_RCV_STATUS_NETWORK_TCP 0x00010000 // TCP
+#define SXG_RCV_STATUS_IPONLY 0x00008000 // IP-only not TCP
+#define SXG_RCV_STATUS_PKT_PRI 0x00006000 // Receive priority
+#define SXG_RCV_STATUS_PKT_PRI_SHFT 13 // Receive priority shift
+#define SXG_RCV_STATUS_PARITY 0x00001000 // MAC Receive RAM parity error
+#define SXG_RCV_STATUS_ADDRESS_MASK 0x00000F00 // Link address detection mask
+#define SXG_RCV_STATUS_ADDRESS_D 0x00000B00 // Link address D
+#define SXG_RCV_STATUS_ADDRESS_C 0x00000A00 // Link address C
+#define SXG_RCV_STATUS_ADDRESS_B 0x00000900 // Link address B
+#define SXG_RCV_STATUS_ADDRESS_A 0x00000800 // Link address A
#define SXG_RCV_STATUS_ADDRESS_BCAST 0x00000300 // Link address broadcast
#define SXG_RCV_STATUS_ADDRESS_MCAST 0x00000200 // Link address multicast
#define SXG_RCV_STATUS_ADDRESS_CMCAST 0x00000100 // Link control multicast
-#define SXG_RCV_STATUS_LINK_MASK 0x000000FF // Link status mask
-#define SXG_RCV_STATUS_LINK_ERROR 0x00000080 // Link error
-#define SXG_RCV_STATUS_LINK_MASK 0x000000FF // Link status mask
-#define SXG_RCV_STATUS_LINK_PARITY 0x00000087 // RcvMacQ parity error
-#define SXG_RCV_STATUS_LINK_EARLY 0x00000086 // Data early
+#define SXG_RCV_STATUS_LINK_MASK 0x000000FF // Link status mask
+#define SXG_RCV_STATUS_LINK_ERROR 0x00000080 // Link error
+#define SXG_RCV_STATUS_LINK_MASK 0x000000FF // Link status mask
+#define SXG_RCV_STATUS_LINK_PARITY 0x00000087 // RcvMacQ parity error
+#define SXG_RCV_STATUS_LINK_EARLY 0x00000086 // Data early
#define SXG_RCV_STATUS_LINK_BUFOFLOW 0x00000085 // Buffer overflow
-#define SXG_RCV_STATUS_LINK_CODE 0x00000084 // Link code error
-#define SXG_RCV_STATUS_LINK_DRIBBLE 0x00000083 // Dribble nibble
-#define SXG_RCV_STATUS_LINK_CRC 0x00000082 // CRC error
-#define SXG_RCV_STATUS_LINK_OFLOW 0x00000081 // Link overflow
-#define SXG_RCV_STATUS_LINK_UFLOW 0x00000080 // Link underflow
-#define SXG_RCV_STATUS_LINK_8023 0x00000020 // 802.3
-#define SXG_RCV_STATUS_LINK_SNAP 0x00000010 // Snap
-#define SXG_RCV_STATUS_LINK_VLAN 0x00000008 // VLAN
+#define SXG_RCV_STATUS_LINK_CODE 0x00000084 // Link code error
+#define SXG_RCV_STATUS_LINK_DRIBBLE 0x00000083 // Dribble nibble
+#define SXG_RCV_STATUS_LINK_CRC 0x00000082 // CRC error
+#define SXG_RCV_STATUS_LINK_OFLOW 0x00000081 // Link overflow
+#define SXG_RCV_STATUS_LINK_UFLOW 0x00000080 // Link underflow
+#define SXG_RCV_STATUS_LINK_8023 0x00000020 // 802.3
+#define SXG_RCV_STATUS_LINK_SNAP 0x00000010 // Snap
+#define SXG_RCV_STATUS_LINK_VLAN 0x00000008 // VLAN
#define SXG_RCV_STATUS_LINK_TYPE_MASK 0x00000007 // Network type mask
-#define SXG_RCV_STATUS_LINK_CONTROL 0x00000003 // Control packet
-#define SXG_RCV_STATUS_LINK_IPV6 0x00000002 // IPv6 packet
-#define SXG_RCV_STATUS_LINK_IPV4 0x00000001 // IPv4 packet
+#define SXG_RCV_STATUS_LINK_CONTROL 0x00000003 // Control packet
+#define SXG_RCV_STATUS_LINK_IPV6 0x00000002 // IPv6 packet
+#define SXG_RCV_STATUS_LINK_IPV4 0x00000001 // IPv4 packet
/***************************************************************************
* Sahara receive and transmit configuration registers
***************************************************************************/
-#define RCV_CONFIG_RESET 0x80000000 // RcvConfig register reset
-#define RCV_CONFIG_ENABLE 0x40000000 // Enable the receive logic
-#define RCV_CONFIG_ENPARSE 0x20000000 // Enable the receive parser
-#define RCV_CONFIG_SOCKET 0x10000000 // Enable the socket detector
-#define RCV_CONFIG_RCVBAD 0x08000000 // Receive all bad frames
-#define RCV_CONFIG_CONTROL 0x04000000 // Receive all control frames
-#define RCV_CONFIG_RCVPAUSE 0x02000000 // Enable pause transmit when attn
-#define RCV_CONFIG_TZIPV6 0x01000000 // Include TCP port w/ IPv6 toeplitz
-#define RCV_CONFIG_TZIPV4 0x00800000 // Include TCP port w/ IPv4 toeplitz
-#define RCV_CONFIG_FLUSH 0x00400000 // Flush buffers
+#define RCV_CONFIG_RESET 0x80000000 // RcvConfig register reset
+#define RCV_CONFIG_ENABLE 0x40000000 // Enable the receive logic
+#define RCV_CONFIG_ENPARSE 0x20000000 // Enable the receive parser
+#define RCV_CONFIG_SOCKET 0x10000000 // Enable the socket detector
+#define RCV_CONFIG_RCVBAD 0x08000000 // Receive all bad frames
+#define RCV_CONFIG_CONTROL 0x04000000 // Receive all control frames
+#define RCV_CONFIG_RCVPAUSE 0x02000000 // Enable pause transmit when attn
+#define RCV_CONFIG_TZIPV6 0x01000000 // Include TCP port w/ IPv6 toeplitz
+#define RCV_CONFIG_TZIPV4 0x00800000 // Include TCP port w/ IPv4 toeplitz
+#define RCV_CONFIG_FLUSH 0x00400000 // Flush buffers
#define RCV_CONFIG_PRIORITY_MASK 0x00300000 // Priority level
#define RCV_CONFIG_HASH_MASK 0x00030000 // Hash depth
-#define RCV_CONFIG_HASH_8 0x00000000 // Hash depth 8
-#define RCV_CONFIG_HASH_16 0x00010000 // Hash depth 16
-#define RCV_CONFIG_HASH_4 0x00020000 // Hash depth 4
-#define RCV_CONFIG_HASH_2 0x00030000 // Hash depth 2
+#define RCV_CONFIG_HASH_8 0x00000000 // Hash depth 8
+#define RCV_CONFIG_HASH_16 0x00010000 // Hash depth 16
+#define RCV_CONFIG_HASH_4 0x00020000 // Hash depth 4
+#define RCV_CONFIG_HASH_2 0x00030000 // Hash depth 2
#define RCV_CONFIG_BUFLEN_MASK 0x0000FFF0 // Buffer length bits 15:4. ie multiple of 16.
-#define RCV_CONFIG_SKT_DIS 0x00000008 // Disable socket detection on attn
+#define RCV_CONFIG_SKT_DIS 0x00000008 // Disable socket detection on attn
// Macro to determine RCV_CONFIG_BUFLEN based on maximum frame size.
// We add 18 bytes for Sahara receive status and padding, plus 4 bytes for CRC,
// and round up to nearest 16 byte boundary
#define RCV_CONFIG_BUFSIZE(_MaxFrame) ((((_MaxFrame) + 22) + 15) & RCV_CONFIG_BUFLEN_MASK)
-#define XMT_CONFIG_RESET 0x80000000 // XmtConfig register reset
-#define XMT_CONFIG_ENABLE 0x40000000 // Enable transmit logic
+#define XMT_CONFIG_RESET 0x80000000 // XmtConfig register reset
+#define XMT_CONFIG_ENABLE 0x40000000 // Enable transmit logic
#define XMT_CONFIG_MAC_PARITY 0x20000000 // Inhibit MAC RAM parity error
#define XMT_CONFIG_BUF_PARITY 0x10000000 // Inhibit D2F buffer parity error
#define XMT_CONFIG_MEM_PARITY 0x08000000 // Inhibit 1T SRAM parity error
@@ -249,9 +249,9 @@ typedef struct _SXG_HW_REGS {
// A-XGMAC Configuration Register 1
#define AXGMAC_CFG1_XMT_PAUSE 0x80000000 // Allow the sending of Pause frames
-#define AXGMAC_CFG1_XMT_EN 0x40000000 // Enable transmit
+#define AXGMAC_CFG1_XMT_EN 0x40000000 // Enable transmit
#define AXGMAC_CFG1_RCV_PAUSE 0x20000000 // Allow the detection of Pause frames
-#define AXGMAC_CFG1_RCV_EN 0x10000000 // Enable receive
+#define AXGMAC_CFG1_RCV_EN 0x10000000 // Enable receive
#define AXGMAC_CFG1_XMT_STATE 0x04000000 // Current transmit state - READ ONLY
#define AXGMAC_CFG1_RCV_STATE 0x01000000 // Current receive state - READ ONLY
#define AXGMAC_CFG1_XOFF_SHORT 0x00001000 // Only pause for 64 slot on XOFF
@@ -262,24 +262,24 @@ typedef struct _SXG_HW_REGS {
#define AXGMAC_CFG1_RCV_FCS2 0x00000200 // Delay receive FCS 2 4-byte words
#define AXGMAC_CFG1_RCV_FCS3 0x00000300 // Delay receive FCS 3 4-byte words
#define AXGMAC_CFG1_PKT_OVERRIDE 0x00000080 // Per-packet override enable
-#define AXGMAC_CFG1_SWAP 0x00000040 // Byte swap enable
+#define AXGMAC_CFG1_SWAP 0x00000040 // Byte swap enable
#define AXGMAC_CFG1_SHORT_ASSERT 0x00000020 // ASSERT srdrpfrm on short frame (<64)
#define AXGMAC_CFG1_RCV_STRICT 0x00000010 // RCV only 802.3AE when CLEAR
#define AXGMAC_CFG1_CHECK_LEN 0x00000008 // Verify frame length
-#define AXGMAC_CFG1_GEN_FCS 0x00000004 // Generate FCS
+#define AXGMAC_CFG1_GEN_FCS 0x00000004 // Generate FCS
#define AXGMAC_CFG1_PAD_MASK 0x00000003 // Mask for pad bits
-#define AXGMAC_CFG1_PAD_64 0x00000001 // Pad frames to 64 bytes
+#define AXGMAC_CFG1_PAD_64 0x00000001 // Pad frames to 64 bytes
#define AXGMAC_CFG1_PAD_VLAN 0x00000002 // Detect VLAN and pad to 68 bytes
-#define AXGMAC_CFG1_PAD_68 0x00000003 // Pad to 68 bytes
+#define AXGMAC_CFG1_PAD_68 0x00000003 // Pad to 68 bytes
// A-XGMAC Configuration Register 2
#define AXGMAC_CFG2_GEN_PAUSE 0x80000000 // Generate single pause frame (test)
#define AXGMAC_CFG2_LF_MANUAL 0x08000000 // Manual link fault sequence
-#define AXGMAC_CFG2_LF_AUTO 0x04000000 // Auto link fault sequence
+#define AXGMAC_CFG2_LF_AUTO 0x04000000 // Auto link fault sequence
#define AXGMAC_CFG2_LF_REMOTE 0x02000000 // Remote link fault (READ ONLY)
#define AXGMAC_CFG2_LF_LOCAL 0x01000000 // Local link fault (READ ONLY)
#define AXGMAC_CFG2_IPG_MASK 0x001F0000 // Inter packet gap
-#define AXGMAC_CFG2_IPG_SHIFT 16
+#define AXGMAC_CFG2_IPG_SHIFT 16
#define AXGMAC_CFG2_PAUSE_XMT 0x00008000 // Pause transmit module
#define AXGMAC_CFG2_IPG_EXTEN 0x00000020 // Enable IPG extension algorithm
#define AXGMAC_CFG2_IPGEX_MASK 0x0000001F // IPG extension
@@ -299,9 +299,9 @@ typedef struct _SXG_HW_REGS {
#define AXGMAC_SARHIGH_OCTET_SIX 0x00FF0000 // Sixth octet
// A-XGMAC Maximum frame length register
-#define AXGMAC_MAXFRAME_XMT 0x3FFF0000 // Maximum transmit frame length
+#define AXGMAC_MAXFRAME_XMT 0x3FFF0000 // Maximum transmit frame length
#define AXGMAC_MAXFRAME_XMT_SHIFT 16
-#define AXGMAC_MAXFRAME_RCV 0x0000FFFF // Maximum receive frame length
+#define AXGMAC_MAXFRAME_RCV 0x0000FFFF // Maximum receive frame length
// This register doesn't need to be written for standard MTU.
// For jumbo, I'll just statically define the value here. This
// value sets the receive byte count to 9036 (0x234C) and the
@@ -324,34 +324,34 @@ typedef struct _SXG_HW_REGS {
// A-XGMAC AMIIM Field Register
#define AXGMAC_AMIIM_FIELD_ST 0xC0000000 // 2-bit ST field
-#define AXGMAC_AMIIM_FIELD_ST_SHIFT 30
+#define AXGMAC_AMIIM_FIELD_ST_SHIFT 30
#define AXGMAC_AMIIM_FIELD_OP 0x30000000 // 2-bit OP field
-#define AXGMAC_AMIIM_FIELD_OP_SHIFT 28
-#define AXGMAC_AMIIM_FIELD_PORT_ADDR 0x0F800000 // Port address field (hstphyadx in spec)
+#define AXGMAC_AMIIM_FIELD_OP_SHIFT 28
+#define AXGMAC_AMIIM_FIELD_PORT_ADDR 0x0F800000 // Port address field (hstphyadx in spec)
#define AXGMAC_AMIIM_FIELD_PORT_SHIFT 23
#define AXGMAC_AMIIM_FIELD_DEV_ADDR 0x007C0000 // Device address field (hstregadx in spec)
#define AXGMAC_AMIIM_FIELD_DEV_SHIFT 18
#define AXGMAC_AMIIM_FIELD_TA 0x00030000 // 2-bit TA field
-#define AXGMAC_AMIIM_FIELD_TA_SHIFT 16
+#define AXGMAC_AMIIM_FIELD_TA_SHIFT 16
#define AXGMAC_AMIIM_FIELD_DATA 0x0000FFFF // Data field
// Values for the AXGMAC_AMIIM_FIELD_OP field in the A-XGMAC AMIIM Field Register
-#define MIIM_OP_ADDR 0 // MIIM Address set operation
-#define MIIM_OP_WRITE 1 // MIIM Write register operation
-#define MIIM_OP_READ 2 // MIIM Read register operation
+#define MIIM_OP_ADDR 0 // MIIM Address set operation
+#define MIIM_OP_WRITE 1 // MIIM Write register operation
+#define MIIM_OP_READ 2 // MIIM Read register operation
#define MIIM_OP_ADDR_SHIFT (MIIM_OP_ADDR << AXGMAC_AMIIM_FIELD_OP_SHIFT)
// Values for the AXGMAC_AMIIM_FIELD_PORT_ADDR field in the A-XGMAC AMIIM Field Register
-#define MIIM_PORT_NUM 1 // All Sahara MIIM modules use port 1
+#define MIIM_PORT_NUM 1 // All Sahara MIIM modules use port 1
// Values for the AXGMAC_AMIIM_FIELD_DEV_ADDR field in the A-XGMAC AMIIM Field Register
-#define MIIM_DEV_PHY_PMA 1 // PHY PMA/PMD module MIIM device number
-#define MIIM_DEV_PHY_PCS 3 // PHY PCS module MIIM device number
-#define MIIM_DEV_PHY_XS 4 // PHY XS module MIIM device number
-#define MIIM_DEV_XGXS 5 // XGXS MIIM device number
+#define MIIM_DEV_PHY_PMA 1 // PHY PMA/PMD module MIIM device number
+#define MIIM_DEV_PHY_PCS 3 // PHY PCS module MIIM device number
+#define MIIM_DEV_PHY_XS 4 // PHY XS module MIIM device number
+#define MIIM_DEV_XGXS 5 // XGXS MIIM device number
// Values for the AXGMAC_AMIIM_FIELD_TA field in the A-XGMAC AMIIM Field Register
-#define MIIM_TA_10GB 2 // set to 2 for 10 GB operation
+#define MIIM_TA_10GB 2 // set to 2 for 10 GB operation
// A-XGMAC AMIIM Configuration Register
#define AXGMAC_AMIIM_CFG_NOPREAM 0x00000080 // Bypass preamble of mngmt frame
@@ -365,25 +365,25 @@ typedef struct _SXG_HW_REGS {
#define AXGMAC_AMIIM_INDC_BUSY 0x00000001 // Set until cmd operation complete
// Link Status and Control Register
-#define LS_PHY_CLR_RESET 0x80000000 // Clear reset signal to PHY
+#define LS_PHY_CLR_RESET 0x80000000 // Clear reset signal to PHY
#define LS_SERDES_POWER_DOWN 0x40000000 // Power down the Sahara Serdes
-#define LS_XGXS_ENABLE 0x20000000 // Enable the XAUI XGXS logic
-#define LS_XGXS_CTL 0x10000000 // Hold XAUI XGXS logic reset until Serdes is up
-#define LS_SERDES_DOWN 0x08000000 // When 0, XAUI Serdes is up and initialization is complete
-#define LS_TRACE_DOWN 0x04000000 // When 0, Trace Serdes is up and initialization is complete
-#define LS_PHY_CLK_25MHZ 0x02000000 // Set PHY clock to 25 MHz (else 156.125 MHz)
-#define LS_PHY_CLK_EN 0x01000000 // Enable clock to PHY
-#define LS_XAUI_LINK_UP 0x00000010 // XAUI link is up
-#define LS_XAUI_LINK_CHNG 0x00000008 // XAUI link status has changed
-#define LS_LINK_ALARM 0x00000004 // Link alarm pin
-#define LS_ATTN_CTRL_MASK 0x00000003 // Mask link attention control bits
-#define LS_ATTN_ALARM 0x00000000 // 00 => Attn on link alarm
+#define LS_XGXS_ENABLE 0x20000000 // Enable the XAUI XGXS logic
+#define LS_XGXS_CTL 0x10000000 // Hold XAUI XGXS logic reset until Serdes is up
+#define LS_SERDES_DOWN 0x08000000 // When 0, XAUI Serdes is up and initialization is complete
+#define LS_TRACE_DOWN 0x04000000 // When 0, Trace Serdes is up and initialization is complete
+#define LS_PHY_CLK_25MHZ 0x02000000 // Set PHY clock to 25 MHz (else 156.125 MHz)
+#define LS_PHY_CLK_EN 0x01000000 // Enable clock to PHY
+#define LS_XAUI_LINK_UP 0x00000010 // XAUI link is up
+#define LS_XAUI_LINK_CHNG 0x00000008 // XAUI link status has changed
+#define LS_LINK_ALARM 0x00000004 // Link alarm pin
+#define LS_ATTN_CTRL_MASK 0x00000003 // Mask link attention control bits
+#define LS_ATTN_ALARM 0x00000000 // 00 => Attn on link alarm
#define LS_ATTN_ALARM_OR_STAT_CHNG 0x00000001 // 01 => Attn on link alarm or status change
-#define LS_ATTN_STAT_CHNG 0x00000002 // 10 => Attn on link status change
-#define LS_ATTN_NONE 0x00000003 // 11 => no Attn
+#define LS_ATTN_STAT_CHNG 0x00000002 // 10 => Attn on link status change
+#define LS_ATTN_NONE 0x00000003 // 11 => no Attn
// Link Address High Registers
-#define LINK_ADDR_ENABLE 0x80000000 // Enable this link address
+#define LINK_ADDR_ENABLE 0x80000000 // Enable this link address
/***************************************************************************
@@ -396,7 +396,7 @@ typedef struct _SXG_HW_REGS {
#define XGXS_ADDRESS_STATUS1 0x0001 // XS Status 1
#define XGXS_ADDRESS_DEVID_LOW 0x0002 // XS Device ID (low)
#define XGXS_ADDRESS_DEVID_HIGH 0x0003 // XS Device ID (high)
-#define XGXS_ADDRESS_SPEED 0x0004 // XS Speed ability
+#define XGXS_ADDRESS_SPEED 0x0004 // XS Speed ability
#define XGXS_ADDRESS_DEV_LOW 0x0005 // XS Devices in package
#define XGXS_ADDRESS_DEV_HIGH 0x0006 // XS Devices in package
#define XGXS_ADDRESS_STATUS2 0x0008 // XS Status 2
@@ -410,27 +410,27 @@ typedef struct _SXG_HW_REGS {
#define XGXS_ADDRESS_RESET_HI2 0x8003 // Vendor-Specific Reset Hi 2
// XS Control 1 register bit definitions
-#define XGXS_CONTROL1_RESET 0x8000 // Reset - self clearing
+#define XGXS_CONTROL1_RESET 0x8000 // Reset - self clearing
#define XGXS_CONTROL1_LOOPBACK 0x4000 // Enable loopback
#define XGXS_CONTROL1_SPEED1 0x2000 // 0 = unspecified, 1 = 10Gb+
#define XGXS_CONTROL1_LOWPOWER 0x0400 // 1 = Low power mode
#define XGXS_CONTROL1_SPEED2 0x0040 // Same as SPEED1 (?)
-#define XGXS_CONTROL1_SPEED 0x003C // Everything reserved except zero (?)
+#define XGXS_CONTROL1_SPEED 0x003C // Everything reserved except zero (?)
// XS Status 1 register bit definitions
-#define XGXS_STATUS1_FAULT 0x0080 // Fault detected
-#define XGXS_STATUS1_LINK 0x0004 // 1 = Link up
+#define XGXS_STATUS1_FAULT 0x0080 // Fault detected
+#define XGXS_STATUS1_LINK 0x0004 // 1 = Link up
#define XGXS_STATUS1_LOWPOWER 0x0002 // 1 = Low power supported
// XS Speed register bit definitions
-#define XGXS_SPEED_10G 0x0001 // 1 = 10G capable
+#define XGXS_SPEED_10G 0x0001 // 1 = 10G capable
// XS Devices register bit definitions
-#define XGXS_DEVICES_DTE 0x0020 // DTE XS Present
-#define XGXS_DEVICES_PHY 0x0010 // PHY XS Present
-#define XGXS_DEVICES_PCS 0x0008 // PCS Present
-#define XGXS_DEVICES_WIS 0x0004 // WIS Present
-#define XGXS_DEVICES_PMD 0x0002 // PMD/PMA Present
+#define XGXS_DEVICES_DTE 0x0020 // DTE XS Present
+#define XGXS_DEVICES_PHY 0x0010 // PHY XS Present
+#define XGXS_DEVICES_PCS 0x0008 // PCS Present
+#define XGXS_DEVICES_WIS 0x0004 // WIS Present
+#define XGXS_DEVICES_PMD 0x0002 // PMD/PMA Present
#define XGXS_DEVICES_CLAUSE22 0x0001 // Clause 22 registers present
// XS Devices High register bit definitions
@@ -444,18 +444,18 @@ typedef struct _SXG_HW_REGS {
#define XGXS_STATUS2_RCV_FAULT 0x0400 // Receive fault
// XS Package ID High register bit definitions
-#define XGXS_PKGID_HIGH_ORG 0xFC00 // Organizationally Unique
-#define XGXS_PKGID_HIGH_MFG 0x03F0 // Manufacturer Model
-#define XGXS_PKGID_HIGH_REV 0x000F // Revision Number
+#define XGXS_PKGID_HIGH_ORG 0xFC00 // Organizationally Unique
+#define XGXS_PKGID_HIGH_MFG 0x03F0 // Manufacturer Model
+#define XGXS_PKGID_HIGH_REV 0x000F // Revision Number
// XS Lane Status register bit definitions
-#define XGXS_LANE_PHY 0x1000 // PHY/DTE lane alignment status
-#define XGXS_LANE_PATTERN 0x0800 // Pattern testing ability
-#define XGXS_LANE_LOOPBACK 0x0400 // PHY loopback ability
-#define XGXS_LANE_SYNC3 0x0008 // Lane 3 sync
-#define XGXS_LANE_SYNC2 0x0004 // Lane 2 sync
-#define XGXS_LANE_SYNC1 0x0002 // Lane 1 sync
-#define XGXS_LANE_SYNC0 0x0001 // Lane 0 sync
+#define XGXS_LANE_PHY 0x1000 // PHY/DTE lane alignment status
+#define XGXS_LANE_PATTERN 0x0800 // Pattern testing ability
+#define XGXS_LANE_LOOPBACK 0x0400 // PHY loopback ability
+#define XGXS_LANE_SYNC3 0x0008 // Lane 3 sync
+#define XGXS_LANE_SYNC2 0x0004 // Lane 2 sync
+#define XGXS_LANE_SYNC1 0x0002 // Lane 1 sync
+#define XGXS_LANE_SYNC0 0x0001 // Lane 0 sync
// XS Test Control register bit definitions
#define XGXS_TEST_PATTERN_ENABLE 0x0004 // Test pattern enabled
@@ -473,10 +473,10 @@ typedef struct _SXG_HW_REGS {
// LASI (Link Alarm Status Interrupt) Registers (located in MIIM_DEV_PHY_PMA device)
#define LASI_RX_ALARM_CONTROL 0x9000 // LASI RX_ALARM Control
#define LASI_TX_ALARM_CONTROL 0x9001 // LASI TX_ALARM Control
-#define LASI_CONTROL 0x9002 // LASI Control
+#define LASI_CONTROL 0x9002 // LASI Control
#define LASI_RX_ALARM_STATUS 0x9003 // LASI RX_ALARM Status
#define LASI_TX_ALARM_STATUS 0x9004 // LASI TX_ALARM Status
-#define LASI_STATUS 0x9005 // LASI Status
+#define LASI_STATUS 0x9005 // LASI Status
// LASI_CONTROL bit definitions
#define LASI_CTL_RX_ALARM_ENABLE 0x0004 // Enable RX_ALARM interrupts
@@ -489,34 +489,34 @@ typedef struct _SXG_HW_REGS {
#define LASI_STATUS_LS_ALARM 0x0001 // Link Status
// PHY registers - PMA/PMD (device 1)
-#define PHY_PMA_CONTROL1 0x0000 // PMA/PMD Control 1
-#define PHY_PMA_STATUS1 0x0001 // PMA/PMD Status 1
-#define PHY_PMA_RCV_DET 0x000A // PMA/PMD Receive Signal Detect
+#define PHY_PMA_CONTROL1 0x0000 // PMA/PMD Control 1
+#define PHY_PMA_STATUS1 0x0001 // PMA/PMD Status 1
+#define PHY_PMA_RCV_DET 0x000A // PMA/PMD Receive Signal Detect
// other PMA/PMD registers exist and can be defined as needed
// PHY registers - PCS (device 3)
-#define PHY_PCS_CONTROL1 0x0000 // PCS Control 1
-#define PHY_PCS_STATUS1 0x0001 // PCS Status 1
-#define PHY_PCS_10G_STATUS1 0x0020 // PCS 10GBASE-R Status 1
+#define PHY_PCS_CONTROL1 0x0000 // PCS Control 1
+#define PHY_PCS_STATUS1 0x0001 // PCS Status 1
+#define PHY_PCS_10G_STATUS1 0x0020 // PCS 10GBASE-R Status 1
// other PCS registers exist and can be defined as needed
// PHY registers - XS (device 4)
-#define PHY_XS_CONTROL1 0x0000 // XS Control 1
-#define PHY_XS_STATUS1 0x0001 // XS Status 1
-#define PHY_XS_LANE_STATUS 0x0018 // XS Lane Status
+#define PHY_XS_CONTROL1 0x0000 // XS Control 1
+#define PHY_XS_STATUS1 0x0001 // XS Status 1
+#define PHY_XS_LANE_STATUS 0x0018 // XS Lane Status
// other XS registers exist and can be defined as needed
// PHY_PMA_CONTROL1 register bit definitions
-#define PMA_CONTROL1_RESET 0x8000 // PMA/PMD reset
+#define PMA_CONTROL1_RESET 0x8000 // PMA/PMD reset
// PHY_PMA_RCV_DET register bit definitions
-#define PMA_RCV_DETECT 0x0001 // PMA/PMD receive signal detect
+#define PMA_RCV_DETECT 0x0001 // PMA/PMD receive signal detect
// PHY_PCS_10G_STATUS1 register bit definitions
-#define PCS_10B_BLOCK_LOCK 0x0001 // PCS 10GBASE-R locked to receive blocks
+#define PCS_10B_BLOCK_LOCK 0x0001 // PCS 10GBASE-R locked to receive blocks
// PHY_XS_LANE_STATUS register bit definitions
-#define XS_LANE_ALIGN 0x1000 // XS transmit lanes aligned
+#define XS_LANE_ALIGN 0x1000 // XS transmit lanes aligned
// PHY Microcode download data structure
typedef struct _PHY_UCODE {
@@ -558,8 +558,8 @@ typedef struct _XMT_DESC {
// command codes
#define XMT_DESC_CMD_RAW_SEND 0 // raw send descriptor
#define XMT_DESC_CMD_CSUM_INSERT 1 // checksum insert descriptor
-#define XMT_DESC_CMD_FORMAT 2 // format descriptor
-#define XMT_DESC_CMD_PRIME 3 // prime descriptor
+#define XMT_DESC_CMD_FORMAT 2 // format descriptor
+#define XMT_DESC_CMD_PRIME 3 // prime descriptor
#define XMT_DESC_CMD_CODE_SHFT 6 // comand code shift (shift to bits [31:30] in word 0)
// shifted command codes
#define XMT_RAW_SEND (XMT_DESC_CMD_RAW_SEND << XMT_DESC_CMD_CODE_SHFT)
@@ -569,22 +569,22 @@ typedef struct _XMT_DESC {
// XMT_DESC Control Byte (XmtCtl) definitions
// NOTE: These bits do not work on Sahara (Rev A)!
-#define XMT_CTL_PAUSE_FRAME 0x80 // current frame is a pause control frame (for statistics)
+#define XMT_CTL_PAUSE_FRAME 0x80 // current frame is a pause control frame (for statistics)
#define XMT_CTL_CONTROL_FRAME 0x40 // current frame is a control frame (for statistics)
#define XMT_CTL_PER_PKT_QUAL 0x20 // per packet qualifier
#define XMT_CTL_PAD_MODE_NONE 0x00 // do not pad frame
-#define XMT_CTL_PAD_MODE_64 0x08 // pad frame to 64 bytes
+#define XMT_CTL_PAD_MODE_64 0x08 // pad frame to 64 bytes
#define XMT_CTL_PAD_MODE_VLAN_68 0x10 // pad frame to 64 bytes, and VLAN frames to 68 bytes
-#define XMT_CTL_PAD_MODE_68 0x18 // pad frame to 68 bytes
-#define XMT_CTL_GEN_FCS 0x04 // generate FCS (CRC) for this frame
-#define XMT_CTL_DELAY_FCS_0 0x00 // do not delay FCS calcution
-#define XMT_CTL_DELAY_FCS_1 0x01 // delay FCS calculation by 1 (4-byte) word
-#define XMT_CTL_DELAY_FCS_2 0x02 // delay FCS calculation by 2 (4-byte) words
-#define XMT_CTL_DELAY_FCS_3 0x03 // delay FCS calculation by 3 (4-byte) words
+#define XMT_CTL_PAD_MODE_68 0x18 // pad frame to 68 bytes
+#define XMT_CTL_GEN_FCS 0x04 // generate FCS (CRC) for this frame
+#define XMT_CTL_DELAY_FCS_0 0x00 // do not delay FCS calcution
+#define XMT_CTL_DELAY_FCS_1 0x01 // delay FCS calculation by 1 (4-byte) word
+#define XMT_CTL_DELAY_FCS_2 0x02 // delay FCS calculation by 2 (4-byte) words
+#define XMT_CTL_DELAY_FCS_3 0x03 // delay FCS calculation by 3 (4-byte) words
// XMT_DESC XmtBufId definition
-#define XMT_BUF_ID_SHFT 8 // The Xmt buffer ID is formed by dividing
- // the buffer (DRAM) address by 256 (or << 8)
+#define XMT_BUF_ID_SHFT 8 // The Xmt buffer ID is formed by dividing
+ // the buffer (DRAM) address by 256 (or << 8)
/*****************************************************************************
* Receiver Sequencer Definitions
@@ -594,8 +594,8 @@ typedef struct _XMT_DESC {
#define RCV_EVTQ_RBFID_MASK 0x0000FFFF // bit mask for the Receive Buffer ID
// Receive Buffer ID definition
-#define RCV_BUF_ID_SHFT 5 // The Rcv buffer ID is formed by dividing
- // the buffer (DRAM) address by 32 (or << 5)
+#define RCV_BUF_ID_SHFT 5 // The Rcv buffer ID is formed by dividing
+ // the buffer (DRAM) address by 32 (or << 5)
// Format of the 18 byte Receive Buffer returned by the
// Receive Sequencer for received packets
@@ -623,48 +623,48 @@ typedef struct _RCV_BUF_HDR {
* Queue definitions
*****************************************************************************/
-// Ingress (read only) queue numbers
-#define PXY_BUF_Q 0 // Proxy Buffer Queue
-#define HST_EVT_Q 1 // Host Event Queue
-#define XMT_BUF_Q 2 // Transmit Buffer Queue
-#define SKT_EVL_Q 3 // RcvSqr Socket Event Low Priority Queue
-#define RCV_EVL_Q 4 // RcvSqr Rcv Event Low Priority Queue
-#define SKT_EVH_Q 5 // RcvSqr Socket Event High Priority Queue
-#define RCV_EVH_Q 6 // RcvSqr Rcv Event High Priority Queue
-#define DMA_RSP_Q 7 // Dma Response Queue - one per CPU context
-// Local (read/write) queue numbers
-#define LOCAL_A_Q 8 // Spare local Queue
-#define LOCAL_B_Q 9 // Spare local Queue
-#define LOCAL_C_Q 10 // Spare local Queue
-#define FSM_EVT_Q 11 // Finite-State-Machine Event Queue
-#define SBF_PAL_Q 12 // System Buffer Physical Address (low) Queue
-#define SBF_PAH_Q 13 // System Buffer Physical Address (high) Queue
-#define SBF_VAL_Q 14 // System Buffer Virtual Address (low) Queue
-#define SBF_VAH_Q 15 // System Buffer Virtual Address (high) Queue
-// Egress (write only) queue numbers
-#define H2G_CMD_Q 16 // Host to GlbRam DMA Command Queue
-#define H2D_CMD_Q 17 // Host to DRAM DMA Command Queue
-#define G2H_CMD_Q 18 // GlbRam to Host DMA Command Queue
-#define G2D_CMD_Q 19 // GlbRam to DRAM DMA Command Queue
-#define D2H_CMD_Q 20 // DRAM to Host DMA Command Queue
-#define D2G_CMD_Q 21 // DRAM to GlbRam DMA Command Queue
-#define D2D_CMD_Q 22 // DRAM to DRAM DMA Command Queue
-#define PXL_CMD_Q 23 // Low Priority Proxy Command Queue
-#define PXH_CMD_Q 24 // High Priority Proxy Command Queue
-#define RSQ_CMD_Q 25 // Receive Sequencer Command Queue
-#define RCV_BUF_Q 26 // Receive Buffer Queue
-
-// Bit definitions for the Proxy Command queues (PXL_CMD_Q and PXH_CMD_Q)
-#define PXY_COPY_EN 0x00200000 // enable copy of xmt descriptor to xmt command queue
-#define PXY_SIZE_16 0x00000000 // copy 16 bytes
-#define PXY_SIZE_32 0x00100000 // copy 32 bytes
+/* Ingress (read only) queue numbers */
+#define PXY_BUF_Q 0 /* Proxy Buffer Queue */
+#define HST_EVT_Q 1 /* Host Event Queue */
+#define XMT_BUF_Q 2 /* Transmit Buffer Queue */
+#define SKT_EVL_Q 3 /* RcvSqr Socket Event Low Priority Queue */
+#define RCV_EVL_Q 4 /* RcvSqr Rcv Event Low Priority Queue */
+#define SKT_EVH_Q 5 /* RcvSqr Socket Event High Priority Queue */
+#define RCV_EVH_Q 6 /* RcvSqr Rcv Event High Priority Queue */
+#define DMA_RSP_Q 7 /* Dma Response Queue - one per CPU context */
+/* Local (read/write) queue numbers */
+#define LOCAL_A_Q 8 /* Spare local Queue */
+#define LOCAL_B_Q 9 /* Spare local Queue */
+#define LOCAL_C_Q 10 /* Spare local Queue */
+#define FSM_EVT_Q 11 /* Finite-State-Machine Event Queue */
+#define SBF_PAL_Q 12 /* System Buffer Physical Address (low) Queue */
+#define SBF_PAH_Q 13 /* System Buffer Physical Address (high) Queue */
+#define SBF_VAL_Q 14 /* System Buffer Virtual Address (low) Queue */
+#define SBF_VAH_Q 15 /* System Buffer Virtual Address (high) Queue */
+/* Egress (write only) queue numbers */
+#define H2G_CMD_Q 16 /* Host to GlbRam DMA Command Queue */
+#define H2D_CMD_Q 17 /* Host to DRAM DMA Command Queue */
+#define G2H_CMD_Q 18 /* GlbRam to Host DMA Command Queue */
+#define G2D_CMD_Q 19 /* GlbRam to DRAM DMA Command Queue */
+#define D2H_CMD_Q 20 /* DRAM to Host DMA Command Queue */
+#define D2G_CMD_Q 21 /* DRAM to GlbRam DMA Command Queue */
+#define D2D_CMD_Q 22 /* DRAM to DRAM DMA Command Queue */
+#define PXL_CMD_Q 23 /* Low Priority Proxy Command Queue */
+#define PXH_CMD_Q 24 /* High Priority Proxy Command Queue */
+#define RSQ_CMD_Q 25 /* Receive Sequencer Command Queue */
+#define RCV_BUF_Q 26 /* Receive Buffer Queue */
+
+/* Bit definitions for the Proxy Command queues (PXL_CMD_Q and PXH_CMD_Q) */
+#define PXY_COPY_EN 0x00200000 /* enable copy of xmt descriptor to xmt command queue */
+#define PXY_SIZE_16 0x00000000 /* copy 16 bytes */
+#define PXY_SIZE_32 0x00100000 /* copy 32 bytes */
/*****************************************************************************
* SXG EEPROM/Flash Configuration Definitions
*****************************************************************************/
#pragma pack(push, 1)
-//
+/* */
typedef struct _HW_CFG_DATA {
ushort Addr;
union {
@@ -673,22 +673,22 @@ typedef struct _HW_CFG_DATA {
};
} HW_CFG_DATA, *PHW_CFG_DATA;
-//
+/* */
#define NUM_HW_CFG_ENTRIES ((128/sizeof(HW_CFG_DATA)) - 4)
-// MAC address
+/* MAC address */
typedef struct _SXG_CONFIG_MAC {
- unsigned char MacAddr[6]; // MAC Address
+ unsigned char MacAddr[6]; /* MAC Address */
} SXG_CONFIG_MAC, *PSXG_CONFIG_MAC;
-//
+/* */
typedef struct _ATK_FRU {
unsigned char PartNum[6];
unsigned char Revision[2];
unsigned char Serial[14];
} ATK_FRU, *PATK_FRU;
-// OEM FRU Format types
+/* OEM FRU Format types */
#define ATK_FRU_FORMAT 0x0000
#define CPQ_FRU_FORMAT 0x0001
#define DELL_FRU_FORMAT 0x0002
@@ -697,24 +697,24 @@ typedef struct _ATK_FRU {
#define EMC_FRU_FORMAT 0x0005
#define NO_FRU_FORMAT 0xFFFF
-// EEPROM/Flash Format
+/* EEPROM/Flash Format */
typedef struct _SXG_CONFIG {
- //
- // Section 1 (128 bytes)
- //
- ushort MagicWord; // EEPROM/FLASH Magic code 'A5A5'
- ushort SpiClks; // SPI bus clock dividers
+ /* */
+ /* Section 1 (128 bytes) */
+ /* */
+ ushort MagicWord; /* EEPROM/FLASH Magic code 'A5A5' */
+ ushort SpiClks; /* SPI bus clock dividers */
HW_CFG_DATA HwCfg[NUM_HW_CFG_ENTRIES];
- //
- //
- //
- ushort Version; // EEPROM format version
- SXG_CONFIG_MAC MacAddr[4]; // space for 4 MAC addresses
- ATK_FRU AtkFru; // FRU information
- ushort OemFruFormat; // OEM FRU format type
- unsigned char OemFru[76]; // OEM FRU information (optional)
- ushort Checksum; // Checksum of section 2
- // CS info XXXTODO
+ /* */
+ /* */
+ /* */
+ ushort Version; /* EEPROM format version */
+ SXG_CONFIG_MAC MacAddr[4]; /* space for 4 MAC addresses */
+ ATK_FRU AtkFru; /* FRU information */
+ ushort OemFruFormat; /* OEM FRU format type */
+ unsigned char OemFru[76]; /* OEM FRU information (optional) */
+ ushort Checksum; /* Checksum of section 2 */
+ /* CS info XXXTODO */
} SXG_CONFIG, *PSXG_CONFIG;
#pragma pack(pop)
@@ -723,12 +723,12 @@ typedef struct _SXG_CONFIG {
*****************************************************************************/
// Sahara (ASIC level) defines
-#define SAHARA_GRAM_SIZE 0x020000 // GRAM size - 128 KB
-#define SAHARA_DRAM_SIZE 0x200000 // DRAM size - 2 MB
-#define SAHARA_QRAM_SIZE 0x004000 // QRAM size - 16K entries (64 KB)
-#define SAHARA_WCS_SIZE 0x002000 // WCS - 8K instructions (x 108 bits)
+#define SAHARA_GRAM_SIZE 0x020000 // GRAM size - 128 KB
+#define SAHARA_DRAM_SIZE 0x200000 // DRAM size - 2 MB
+#define SAHARA_QRAM_SIZE 0x004000 // QRAM size - 16K entries (64 KB)
+#define SAHARA_WCS_SIZE 0x002000 // WCS - 8K instructions (x 108 bits)
// Arabia (board level) defines
-#define FLASH_SIZE 0x080000 // 512 KB (4 Mb)
-#define EEPROM_SIZE_XFMR 512 // true EEPROM size (bytes), including xfmr area
-#define EEPROM_SIZE_NO_XFMR 256 // EEPROM size excluding xfmr area
+#define FLASH_SIZE 0x080000 // 512 KB (4 Mb)
+#define EEPROM_SIZE_XFMR 512 // true EEPROM size (bytes), including xfmr area
+#define EEPROM_SIZE_NO_XFMR 256 // EEPROM size excluding xfmr area
diff --git a/drivers/staging/sxg/sxgphycode.h b/drivers/staging/sxg/sxgphycode.h
index 26b36c81eb1..8dbaeda7eca 100644
--- a/drivers/staging/sxg/sxgphycode.h
+++ b/drivers/staging/sxg/sxgphycode.h
@@ -34,7 +34,7 @@ static PHY_UCODE PhyUcode[] = {
*/
/* Addr, Data */
{0xc017, 0xfeb0}, /* flip RX_LOS polarity (mandatory */
- /* patch for SFP+ applications) */
+ /* patch for SFP+ applications) */
{0xC001, 0x0428}, /* flip RX serial polarity */
{0xc013, 0xf341}, /* invert lxmit clock (mandatory patch) */
@@ -43,7 +43,7 @@ static PHY_UCODE PhyUcode[] = {
{0xc210, 0x8000}, /* reset datapath (mandatory patch) */
{0xc210, 0x0000}, /* reset datapath (mandatory patch) */
{0x0000, 0x0032}, /* wait for 50ms for datapath reset to */
- /* complete. (mandatory patch) */
+ /* complete. (mandatory patch) */
/* Configure the LED's */
{0xc214, 0x0099}, /* configure the LED drivers */
@@ -52,15 +52,15 @@ static PHY_UCODE PhyUcode[] = {
/* Transceiver-specific MDIO Patches: */
{0xc010, 0x448a}, /* (bit 14) mask out high BER input from the */
- /* LOS signal in 1.000A */
- /* (mandatory patch for SR code)*/
+ /* LOS signal in 1.000A */
+ /* (mandatory patch for SR code) */
{0xc003, 0x0181}, /* (bit 7) enable the CDR inc setting in */
- /* 1.C005 (mandatory patch for SR code) */
+ /* 1.C005 (mandatory patch for SR code) */
/* Transceiver-specific Microcontroller Initialization: */
{0xc04a, 0x5200}, /* activate microcontroller and pause */
{0x0000, 0x0032}, /* wait 50ms for microcontroller before */
- /* writing in code. */
+ /* writing in code. */
/* code block starts here: */
{0xcc00, 0x2009},
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index e64918f42ff..72e209276ea 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -221,7 +221,7 @@ static void usbip_dump_request_type(__u8 rt)
static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd)
{
if (!cmd) {
- printk(" %s : null pointer\n", __FUNCTION__);
+ printk(" %s : null pointer\n", __func__);
return;
}
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index 933ccaf50af..58e3995d0e2 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -202,7 +202,7 @@ static void vhci_rx_pdu(struct usbip_device *ud)
ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0);
if (ret != sizeof(pdu)) {
uerr("receiving pdu failed! size is %d, should be %d\n",
- ret, sizeof(pdu));
+ ret, (unsigned int)sizeof(pdu));
usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
return;
}
diff --git a/drivers/staging/winbond/Kconfig b/drivers/staging/winbond/Kconfig
index 10d72bec88a..425219ed7ab 100644
--- a/drivers/staging/winbond/Kconfig
+++ b/drivers/staging/winbond/Kconfig
@@ -1,6 +1,6 @@
config W35UND
tristate "Winbond driver"
- depends on MAC80211 && WLAN_80211 && EXPERIMENTAL && !4KSTACKS
+ depends on MAC80211 && WLAN_80211 && USB && EXPERIMENTAL && !4KSTACKS
default n
---help---
This is highly experimental driver for winbond wifi card on some Kohjinsha notebooks
diff --git a/drivers/staging/winbond/README b/drivers/staging/winbond/README
index 707b6b354dc..cb944e4bf17 100644
--- a/drivers/staging/winbond/README
+++ b/drivers/staging/winbond/README
@@ -5,6 +5,7 @@ TODO:
- remove typedefs
- remove unused ioctls
- use cfg80211 for regulatory stuff
+ - fix 4k stack problems
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
Pavel Machek <pavel@suse.cz>
diff --git a/drivers/staging/winbond/bss_f.h b/drivers/staging/winbond/bss_f.h
index c957bc94f08..01318315399 100644
--- a/drivers/staging/winbond/bss_f.h
+++ b/drivers/staging/winbond/bss_f.h
@@ -24,7 +24,7 @@ void DesiredRate2InfoElement(PWB32_ADAPTER Adapter, u8 *addr, u16 *iFildOffset,
u8 *pBasicRateSet, u8 BasicRateCount,
u8 *pOperationRateSet, u8 OperationRateCount);
void BSSAddIBSSdata(PWB32_ADAPTER Adapter, PWB_BSSDESCRIPTION psDesData);
-unsigned char boCmpMacAddr( PUCHAR, PUCHAR );
+unsigned char boCmpMacAddr( u8 *, u8 *);
unsigned char boCmpSSID(struct SSID_Element *psSSID1, struct SSID_Element *psSSID2);
u16 wBSSfindSSID(PWB32_ADAPTER Adapter, struct SSID_Element *psSsid);
u16 wRoamingQuery(PWB32_ADAPTER Adapter);
@@ -42,11 +42,11 @@ void RateReSortForSRate(PWB32_ADAPTER Adapter, u8 *RateArray, u8 num);
void Assemble_IE(PWB32_ADAPTER Adapter, u16 wBssIdx);
void SetMaxTxRate(PWB32_ADAPTER Adapter);
-void CreateWpaIE(PWB32_ADAPTER Adapter, u16* iFildOffset, PUCHAR msg, struct Management_Frame* msgHeader,
+void CreateWpaIE(PWB32_ADAPTER Adapter, u16* iFildOffset, u8 *msg, struct Management_Frame* msgHeader,
struct Association_Request_Frame_Body* msgBody, u16 iMSindex); //added by WS 05/14/05
#ifdef _WPA2_
-void CreateRsnIE(PWB32_ADAPTER Adapter, u16* iFildOffset, PUCHAR msg, struct Management_Frame* msgHeader,
+void CreateRsnIE(PWB32_ADAPTER Adapter, u16* iFildOffset, u8 *msg, struct Management_Frame* msgHeader,
struct Association_Request_Frame_Body* msgBody, u16 iMSindex);//added by WS 05/14/05
u16 SearchPmkid(PWB32_ADAPTER Adapter, struct Management_Frame* msgHeader,
diff --git a/drivers/staging/winbond/ds_tkip.h b/drivers/staging/winbond/ds_tkip.h
index 29e5055b45a..6841d66e7e8 100644
--- a/drivers/staging/winbond/ds_tkip.h
+++ b/drivers/staging/winbond/ds_tkip.h
@@ -25,9 +25,9 @@ typedef struct tkip
s32 bytes_in_M; // # bytes in M
} tkip_t;
-//void _append_data( PUCHAR pData, u16 size, tkip_t *p );
-void Mds_MicGet( void* Adapter, void* pRxLayer1, PUCHAR pKey, PUCHAR pMic );
-void Mds_MicFill( void* Adapter, void* pDes, PUCHAR XmitBufAddress );
+//void _append_data( u8 *pData, u16 size, tkip_t *p );
+void Mds_MicGet( void* Adapter, void* pRxLayer1, u8 *pKey, u8 *pMic );
+void Mds_MicFill( void* Adapter, void* pDes, u8 *XmitBufAddress );
diff --git a/drivers/staging/winbond/linux/common.h b/drivers/staging/winbond/linux/common.h
index 6b00bad74f7..712a86cfa68 100644
--- a/drivers/staging/winbond/linux/common.h
+++ b/drivers/staging/winbond/linux/common.h
@@ -39,14 +39,6 @@
// Common type definition
//===============================================================
-typedef u8* PUCHAR;
-typedef s8* PCHAR;
-typedef u8* PBOOLEAN;
-typedef u16* PUSHORT;
-typedef u32* PULONG;
-typedef s16* PSHORT;
-
-
//===========================================
#define IGNORE 2
#define SUCCESS 1
@@ -110,16 +102,9 @@ typedef struct urb * PURB;
#define OS_ATOMIC_READ( _A, _V ) _V
#define OS_ATOMIC_INC( _A, _V ) EncapAtomicInc( _A, (void*)_V )
#define OS_ATOMIC_DEC( _A, _V ) EncapAtomicDec( _A, (void*)_V )
-#define OS_MEMORY_CLEAR( _A, _S ) memset( (PUCHAR)_A,0,_S)
+#define OS_MEMORY_CLEAR( _A, _S ) memset( (u8 *)_A,0,_S)
#define OS_MEMORY_COMPARE( _A, _B, _S ) (memcmp(_A,_B,_S)? 0 : 1) // Definition is reverse with Ndis 1: the same 0: different
-
-#define OS_SPIN_LOCK spinlock_t
-#define OS_SPIN_LOCK_ALLOCATE( _S ) spin_lock_init( _S );
-#define OS_SPIN_LOCK_FREE( _S )
-#define OS_SPIN_LOCK_ACQUIRED( _S ) spin_lock_irq( _S )
-#define OS_SPIN_LOCK_RELEASED( _S ) spin_unlock_irq( _S );
-
#define OS_TIMER struct timer_list
#define OS_TIMER_INITIAL( _T, _F, _P ) \
{ \
diff --git a/drivers/staging/winbond/linux/wb35reg.c b/drivers/staging/winbond/linux/wb35reg.c
index 2c0b454e8ca..ebb6db5438a 100644
--- a/drivers/staging/winbond/linux/wb35reg.c
+++ b/drivers/staging/winbond/linux/wb35reg.c
@@ -10,7 +10,7 @@ extern void phy_calibration_winbond(hw_data_t *phw_data, u32 frequency);
// Flag : AUTO_INCREMENT - RegisterNo will auto increment 4
// NO_INCREMENT - Function will write data into the same register
unsigned char
-Wb35Reg_BurstWrite(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8 NumberOfData, u8 Flag)
+Wb35Reg_BurstWrite(phw_data_t pHwData, u16 RegisterNo, u32 * pRegisterData, u8 NumberOfData, u8 Flag)
{
PWB35REG pWb35Reg = &pHwData->Wb35Reg;
PURB pUrb = NULL;
@@ -30,13 +30,13 @@ Wb35Reg_BurstWrite(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8
if( pUrb && pRegQueue ) {
pRegQueue->DIRECT = 2;// burst write register
pRegQueue->INDEX = RegisterNo;
- pRegQueue->pBuffer = (PULONG)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ pRegQueue->pBuffer = (u32 *)((u8 *)pRegQueue + sizeof(REG_QUEUE));
memcpy( pRegQueue->pBuffer, pRegisterData, DataSize );
//the function for reversing register data from little endian to big endian
for( i=0; i<NumberOfData ; i++ )
pRegQueue->pBuffer[i] = cpu_to_le32( pRegQueue->pBuffer[i] );
- dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE) + DataSize);
+ dr = (struct usb_ctrlrequest *)((u8 *)pRegQueue + sizeof(REG_QUEUE) + DataSize);
dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE;
dr->bRequest = 0x04; // USB or vendor-defined request code, burst mode
dr->wValue = cpu_to_le16( Flag ); // 0: Register number auto-increment, 1: No auto increment
@@ -46,14 +46,14 @@ Wb35Reg_BurstWrite(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8
pRegQueue->pUsbReq = dr;
pRegQueue->pUrb = pUrb;
- OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ spin_lock_irq( &pWb35Reg->EP0VM_spin_lock );
if (pWb35Reg->pRegFirst == NULL)
pWb35Reg->pRegFirst = pRegQueue;
else
pWb35Reg->pRegLast->Next = pRegQueue;
pWb35Reg->pRegLast = pRegQueue;
- OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+ spin_unlock_irq( &pWb35Reg->EP0VM_spin_lock );
// Start EP0VM
Wb35Reg_EP0VM_start(pHwData);
@@ -181,7 +181,7 @@ Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue )
pRegQueue->INDEX = RegisterNo;
pRegQueue->VALUE = cpu_to_le32(RegisterValue);
pRegQueue->RESERVED_VALID = FALSE;
- dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ dr = (struct usb_ctrlrequest *)((u8 *)pRegQueue + sizeof(REG_QUEUE));
dr->bRequestType = USB_TYPE_VENDOR|USB_DIR_OUT |USB_RECIP_DEVICE;
dr->bRequest = 0x03; // USB or vendor-defined request code, burst mode
dr->wValue = cpu_to_le16(0x0);
@@ -193,14 +193,14 @@ Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue )
pRegQueue->pUsbReq = dr;
pRegQueue->pUrb = pUrb;
- OS_SPIN_LOCK_ACQUIRED(&pWb35Reg->EP0VM_spin_lock );
+ spin_lock_irq(&pWb35Reg->EP0VM_spin_lock );
if (pWb35Reg->pRegFirst == NULL)
pWb35Reg->pRegFirst = pRegQueue;
else
pWb35Reg->pRegLast->Next = pRegQueue;
pWb35Reg->pRegLast = pRegQueue;
- OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+ spin_unlock_irq( &pWb35Reg->EP0VM_spin_lock );
// Start EP0VM
Wb35Reg_EP0VM_start(pHwData);
@@ -220,7 +220,7 @@ Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue )
// FALSE : register not support
unsigned char
Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue,
- PCHAR pValue, s8 Len)
+ s8 *pValue, s8 Len)
{
PWB35REG pWb35Reg = &pHwData->Wb35Reg;
struct usb_ctrlrequest *dr;
@@ -243,7 +243,7 @@ Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData, u16 RegisterNo, u32 Register
//NOTE : Users must guarantee the size of value will not exceed the buffer size.
memcpy(pRegQueue->RESERVED, pValue, Len);
pRegQueue->RESERVED_VALID = TRUE;
- dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ dr = (struct usb_ctrlrequest *)((u8 *)pRegQueue + sizeof(REG_QUEUE));
dr->bRequestType = USB_TYPE_VENDOR|USB_DIR_OUT |USB_RECIP_DEVICE;
dr->bRequest = 0x03; // USB or vendor-defined request code, burst mode
dr->wValue = cpu_to_le16(0x0);
@@ -254,14 +254,14 @@ Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData, u16 RegisterNo, u32 Register
pRegQueue->Next = NULL;
pRegQueue->pUsbReq = dr;
pRegQueue->pUrb = pUrb;
- OS_SPIN_LOCK_ACQUIRED (&pWb35Reg->EP0VM_spin_lock );
+ spin_lock_irq (&pWb35Reg->EP0VM_spin_lock );
if( pWb35Reg->pRegFirst == NULL )
pWb35Reg->pRegFirst = pRegQueue;
else
pWb35Reg->pRegLast->Next = pRegQueue;
pWb35Reg->pRegLast = pRegQueue;
- OS_SPIN_LOCK_RELEASED ( &pWb35Reg->EP0VM_spin_lock );
+ spin_unlock_irq ( &pWb35Reg->EP0VM_spin_lock );
// Start EP0VM
Wb35Reg_EP0VM_start(pHwData);
@@ -278,10 +278,10 @@ Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData, u16 RegisterNo, u32 Register
// FALSE : register not support
// pRegisterValue : It must be a resident buffer due to asynchronous read register.
unsigned char
-Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue )
+Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, u32 * pRegisterValue )
{
PWB35REG pWb35Reg = &pHwData->Wb35Reg;
- PULONG pltmp = pRegisterValue;
+ u32 * pltmp = pRegisterValue;
int ret = -1;
// Module shutdown
@@ -327,7 +327,7 @@ Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue
// FALSE : register not support
// pRegisterValue : It must be a resident buffer due to asynchronous read register.
unsigned char
-Wb35Reg_Read(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue )
+Wb35Reg_Read(phw_data_t pHwData, u16 RegisterNo, u32 * pRegisterValue )
{
PWB35REG pWb35Reg = &pHwData->Wb35Reg;
struct usb_ctrlrequest * dr;
@@ -348,7 +348,7 @@ Wb35Reg_Read(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue )
pRegQueue->DIRECT = 0;// read register
pRegQueue->INDEX = RegisterNo;
pRegQueue->pBuffer = pRegisterValue;
- dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ dr = (struct usb_ctrlrequest *)((u8 *)pRegQueue + sizeof(REG_QUEUE));
dr->bRequestType = USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN;
dr->bRequest = 0x01; // USB or vendor-defined request code, burst mode
dr->wValue = cpu_to_le16(0x0);
@@ -359,14 +359,14 @@ Wb35Reg_Read(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue )
pRegQueue->Next = NULL;
pRegQueue->pUsbReq = dr;
pRegQueue->pUrb = pUrb;
- OS_SPIN_LOCK_ACQUIRED ( &pWb35Reg->EP0VM_spin_lock );
+ spin_lock_irq ( &pWb35Reg->EP0VM_spin_lock );
if( pWb35Reg->pRegFirst == NULL )
pWb35Reg->pRegFirst = pRegQueue;
else
pWb35Reg->pRegLast->Next = pRegQueue;
pWb35Reg->pRegLast = pRegQueue;
- OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+ spin_unlock_irq( &pWb35Reg->EP0VM_spin_lock );
// Start EP0VM
Wb35Reg_EP0VM_start( pHwData );
@@ -399,7 +399,7 @@ Wb35Reg_EP0VM(phw_data_t pHwData )
PWB35REG pWb35Reg = &pHwData->Wb35Reg;
PURB pUrb;
struct usb_ctrlrequest *dr;
- PULONG pBuffer;
+ u32 * pBuffer;
int ret = -1;
PREG_QUEUE pRegQueue;
@@ -411,9 +411,9 @@ Wb35Reg_EP0VM(phw_data_t pHwData )
goto cleanup;
// Get the register data and send to USB through Irp
- OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ spin_lock_irq( &pWb35Reg->EP0VM_spin_lock );
pRegQueue = pWb35Reg->pRegFirst;
- OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+ spin_unlock_irq( &pWb35Reg->EP0VM_spin_lock );
if (!pRegQueue)
goto cleanup;
@@ -429,7 +429,7 @@ Wb35Reg_EP0VM(phw_data_t pHwData )
usb_fill_control_urb( pUrb, pHwData->WbUsb.udev,
REG_DIRECTION(pHwData->WbUsb.udev,pRegQueue),
- (PUCHAR)dr,pBuffer,cpu_to_le16(dr->wLength),
+ (u8 *)dr,pBuffer,cpu_to_le16(dr->wLength),
Wb35Reg_EP0VM_complete, (void*)pHwData);
pWb35Reg->EP0vm_state = VM_RUNNING;
@@ -468,12 +468,12 @@ Wb35Reg_EP0VM_complete(PURB pUrb)
OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount );
} else {
// Complete to send, remove the URB from the first
- OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ spin_lock_irq( &pWb35Reg->EP0VM_spin_lock );
pRegQueue = pWb35Reg->pRegFirst;
if (pRegQueue == pWb35Reg->pRegLast)
pWb35Reg->pRegLast = NULL;
pWb35Reg->pRegFirst = pWb35Reg->pRegFirst->Next;
- OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+ spin_unlock_irq( &pWb35Reg->EP0VM_spin_lock );
if (pWb35Reg->EP0VM_status) {
#ifdef _PE_REG_DUMP_
@@ -513,7 +513,7 @@ Wb35Reg_destroy(phw_data_t pHwData)
OS_SLEEP(10000); // Delay for waiting function enter 940623.1.b
// Release all the data in RegQueue
- OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ spin_lock_irq( &pWb35Reg->EP0VM_spin_lock );
pRegQueue = pWb35Reg->pRegFirst;
while (pRegQueue) {
if (pRegQueue == pWb35Reg->pRegLast)
@@ -521,7 +521,7 @@ Wb35Reg_destroy(phw_data_t pHwData)
pWb35Reg->pRegFirst = pWb35Reg->pRegFirst->Next;
pUrb = pRegQueue->pUrb;
- OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+ spin_unlock_irq( &pWb35Reg->EP0VM_spin_lock );
if (pUrb) {
usb_free_urb(pUrb);
kfree(pRegQueue);
@@ -530,14 +530,11 @@ Wb35Reg_destroy(phw_data_t pHwData)
WBDEBUG(("EP0 queue release error\n"));
#endif
}
- OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ spin_lock_irq( &pWb35Reg->EP0VM_spin_lock );
pRegQueue = pWb35Reg->pRegFirst;
}
- OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
-
- // Free resource
- OS_SPIN_LOCK_FREE( &pWb35Reg->EP0VM_spin_lock );
+ spin_unlock_irq( &pWb35Reg->EP0VM_spin_lock );
}
//====================================================================================
@@ -550,7 +547,7 @@ unsigned char Wb35Reg_initial(phw_data_t pHwData)
u32 SoftwareSet, VCO_trim, TxVga, Region_ScanInterval;
// Spin lock is acquired for read and write IRP command
- OS_SPIN_LOCK_ALLOCATE( &pWb35Reg->EP0VM_spin_lock );
+ spin_lock_init( &pWb35Reg->EP0VM_spin_lock );
// Getting RF module type from EEPROM ------------------------------------
Wb35Reg_WriteSync( pHwData, 0x03b4, 0x080d0000 ); // Start EEPROM access + Read + address(0x0d)
@@ -655,7 +652,7 @@ unsigned char Wb35Reg_initial(phw_data_t pHwData)
// version in _GENREQ.ASM of the DWB NE1000/2000 driver.
//==================================================================================
u32
-CardComputeCrc(PUCHAR Buffer, u32 Length)
+CardComputeCrc(u8 * Buffer, u32 Length)
{
u32 Crc, Carry;
u32 i, j;
diff --git a/drivers/staging/winbond/linux/wb35reg_f.h b/drivers/staging/winbond/linux/wb35reg_f.h
index 38e2906b51a..3006cfe99cc 100644
--- a/drivers/staging/winbond/linux/wb35reg_f.h
+++ b/drivers/staging/winbond/linux/wb35reg_f.h
@@ -29,16 +29,16 @@ void EEPROMTxVgaAdjust( phw_data_t pHwData ); // 20060619.5 Add
void Wb35Reg_destroy( phw_data_t pHwData );
-unsigned char Wb35Reg_Read( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue );
-unsigned char Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue );
+unsigned char Wb35Reg_Read( phw_data_t pHwData, u16 RegisterNo, u32 * pRegisterValue );
+unsigned char Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, u32 * pRegisterValue );
unsigned char Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue );
unsigned char Wb35Reg_WriteSync( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue );
unsigned char Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData,
u16 RegisterNo,
u32 RegisterValue,
- PCHAR pValue,
- s8 Len);
-unsigned char Wb35Reg_BurstWrite( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8 NumberOfData, u8 Flag );
+ s8 *pValue,
+ s8 Len);
+unsigned char Wb35Reg_BurstWrite( phw_data_t pHwData, u16 RegisterNo, u32 * pRegisterData, u8 NumberOfData, u8 Flag );
void Wb35Reg_EP0VM( phw_data_t pHwData );
void Wb35Reg_EP0VM_start( phw_data_t pHwData );
@@ -47,7 +47,7 @@ void Wb35Reg_EP0VM_complete( PURB pUrb );
u32 BitReverse( u32 dwData, u32 DataLength);
void CardGetMulticastBit( u8 Address[MAC_ADDR_LENGTH], u8 *Byte, u8 *Value );
-u32 CardComputeCrc( PUCHAR Buffer, u32 Length );
+u32 CardComputeCrc( u8 * Buffer, u32 Length );
void Wb35Reg_phy_calibration( phw_data_t pHwData );
void Wb35Reg_Update( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue );
diff --git a/drivers/staging/winbond/linux/wb35reg_s.h b/drivers/staging/winbond/linux/wb35reg_s.h
index a7595b1e733..8b35b93f7f0 100644
--- a/drivers/staging/winbond/linux/wb35reg_s.h
+++ b/drivers/staging/winbond/linux/wb35reg_s.h
@@ -75,7 +75,7 @@ typedef struct _REG_QUEUE
union
{
u32 VALUE;
- PULONG pBuffer;
+ u32 * pBuffer;
};
u8 RESERVED[4];// space reserved for communication
@@ -143,7 +143,7 @@ typedef struct _WB35REG
//-------------------
// VM
//-------------------
- OS_SPIN_LOCK EP0VM_spin_lock; // 4B
+ spinlock_t EP0VM_spin_lock; // 4B
u32 EP0VM_status;//$$
PREG_QUEUE pRegFirst;
PREG_QUEUE pRegLast;
diff --git a/drivers/staging/winbond/linux/wb35rx.c b/drivers/staging/winbond/linux/wb35rx.c
index 26157eb3d5a..b4b9f5f371d 100644
--- a/drivers/staging/winbond/linux/wb35rx.c
+++ b/drivers/staging/winbond/linux/wb35rx.c
@@ -27,7 +27,7 @@ void Wb35Rx_start(phw_data_t pHwData)
void Wb35Rx( phw_data_t pHwData )
{
PWB35RX pWb35Rx = &pHwData->Wb35Rx;
- PUCHAR pRxBufferAddress;
+ u8 * pRxBufferAddress;
PURB pUrb = (PURB)pWb35Rx->RxUrb;
int retv;
u32 RxBufferId;
@@ -35,51 +35,50 @@ void Wb35Rx( phw_data_t pHwData )
//
// Issuing URB
//
- do {
- if (pHwData->SurpriseRemove || pHwData->HwStop)
- break;
+ if (pHwData->SurpriseRemove || pHwData->HwStop)
+ goto error;
- if (pWb35Rx->rx_halt)
- break;
+ if (pWb35Rx->rx_halt)
+ goto error;
- // Get RxBuffer's ID
- RxBufferId = pWb35Rx->RxBufferId;
- if (!pWb35Rx->RxOwner[RxBufferId]) {
- // It's impossible to run here.
- #ifdef _PE_RX_DUMP_
- WBDEBUG(("Rx driver fifo unavailable\n"));
- #endif
- break;
- }
+ // Get RxBuffer's ID
+ RxBufferId = pWb35Rx->RxBufferId;
+ if (!pWb35Rx->RxOwner[RxBufferId]) {
+ // It's impossible to run here.
+ #ifdef _PE_RX_DUMP_
+ WBDEBUG(("Rx driver fifo unavailable\n"));
+ #endif
+ goto error;
+ }
- // Update buffer point, then start to bulkin the data from USB
- pWb35Rx->RxBufferId++;
- pWb35Rx->RxBufferId %= MAX_USB_RX_BUFFER_NUMBER;
+ // Update buffer point, then start to bulkin the data from USB
+ pWb35Rx->RxBufferId++;
+ pWb35Rx->RxBufferId %= MAX_USB_RX_BUFFER_NUMBER;
- pWb35Rx->CurrentRxBufferId = RxBufferId;
+ pWb35Rx->CurrentRxBufferId = RxBufferId;
- if (1 != OS_MEMORY_ALLOC((void* *)&pWb35Rx->pDRx, MAX_USB_RX_BUFFER)) {
- printk("w35und: Rx memory alloc failed\n");
- break;
- }
- pRxBufferAddress = pWb35Rx->pDRx;
+ if (1 != OS_MEMORY_ALLOC((void* *)&pWb35Rx->pDRx, MAX_USB_RX_BUFFER)) {
+ printk("w35und: Rx memory alloc failed\n");
+ goto error;
+ }
+ pRxBufferAddress = pWb35Rx->pDRx;
- usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
- usb_rcvbulkpipe(pHwData->WbUsb.udev, 3),
- pRxBufferAddress, MAX_USB_RX_BUFFER,
- Wb35Rx_Complete, pHwData);
+ usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
+ usb_rcvbulkpipe(pHwData->WbUsb.udev, 3),
+ pRxBufferAddress, MAX_USB_RX_BUFFER,
+ Wb35Rx_Complete, pHwData);
- pWb35Rx->EP3vm_state = VM_RUNNING;
+ pWb35Rx->EP3vm_state = VM_RUNNING;
- retv = wb_usb_submit_urb(pUrb);
+ retv = wb_usb_submit_urb(pUrb);
- if (retv != 0) {
- printk("Rx URB sending error\n");
- break;
- }
- return;
- } while(FALSE);
+ if (retv != 0) {
+ printk("Rx URB sending error\n");
+ goto error;
+ }
+ return;
+error:
// VM stop
pWb35Rx->EP3vm_state = VM_STOP;
OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Rx->RxFireCounter );
@@ -89,7 +88,7 @@ void Wb35Rx_Complete(PURB pUrb)
{
phw_data_t pHwData = pUrb->context;
PWB35RX pWb35Rx = &pHwData->Wb35Rx;
- PUCHAR pRxBufferAddress;
+ u8 * pRxBufferAddress;
u32 SizeCheck;
u16 BulkLength;
u32 RxBufferId;
@@ -99,65 +98,63 @@ void Wb35Rx_Complete(PURB pUrb)
pWb35Rx->EP3vm_state = VM_COMPLETED;
pWb35Rx->EP3VM_status = pUrb->status;//Store the last result of Irp
- do {
- RxBufferId = pWb35Rx->CurrentRxBufferId;
+ RxBufferId = pWb35Rx->CurrentRxBufferId;
- pRxBufferAddress = pWb35Rx->pDRx;
- BulkLength = (u16)pUrb->actual_length;
+ pRxBufferAddress = pWb35Rx->pDRx;
+ BulkLength = (u16)pUrb->actual_length;
- // The IRP is completed
- pWb35Rx->EP3vm_state = VM_COMPLETED;
+ // The IRP is completed
+ pWb35Rx->EP3vm_state = VM_COMPLETED;
- if (pHwData->SurpriseRemove || pHwData->HwStop) // Must be here, or RxBufferId is invalid
- break;
+ if (pHwData->SurpriseRemove || pHwData->HwStop) // Must be here, or RxBufferId is invalid
+ goto error;
- if (pWb35Rx->rx_halt)
- break;
+ if (pWb35Rx->rx_halt)
+ goto error;
- // Start to process the data only in successful condition
- pWb35Rx->RxOwner[ RxBufferId ] = 0; // Set the owner to driver
- R00.value = le32_to_cpu(*(PULONG)pRxBufferAddress);
+ // Start to process the data only in successful condition
+ pWb35Rx->RxOwner[ RxBufferId ] = 0; // Set the owner to driver
+ R00.value = le32_to_cpu(*(u32 *)pRxBufferAddress);
- // The URB is completed, check the result
- if (pWb35Rx->EP3VM_status != 0) {
- #ifdef _PE_USB_STATE_DUMP_
- WBDEBUG(("EP3 IoCompleteRoutine return error\n"));
- DebugUsbdStatusInformation( pWb35Rx->EP3VM_status );
- #endif
- pWb35Rx->EP3vm_state = VM_STOP;
- break;
- }
+ // The URB is completed, check the result
+ if (pWb35Rx->EP3VM_status != 0) {
+ #ifdef _PE_USB_STATE_DUMP_
+ WBDEBUG(("EP3 IoCompleteRoutine return error\n"));
+ DebugUsbdStatusInformation( pWb35Rx->EP3VM_status );
+ #endif
+ pWb35Rx->EP3vm_state = VM_STOP;
+ goto error;
+ }
- // 20060220 For recovering. check if operating in single USB mode
- if (!HAL_USB_MODE_BURST(pHwData)) {
- SizeCheck = R00.R00_receive_byte_count; //20060926 anson's endian
- if ((SizeCheck & 0x03) > 0)
- SizeCheck -= 4;
- SizeCheck = (SizeCheck + 3) & ~0x03;
- SizeCheck += 12; // 8 + 4 badbeef
- if ((BulkLength > 1600) ||
- (SizeCheck > 1600) ||
- (BulkLength != SizeCheck) ||
- (BulkLength == 0)) { // Add for fail Urb
- pWb35Rx->EP3vm_state = VM_STOP;
- pWb35Rx->Ep3ErrorCount2++;
- }
+ // 20060220 For recovering. check if operating in single USB mode
+ if (!HAL_USB_MODE_BURST(pHwData)) {
+ SizeCheck = R00.R00_receive_byte_count; //20060926 anson's endian
+ if ((SizeCheck & 0x03) > 0)
+ SizeCheck -= 4;
+ SizeCheck = (SizeCheck + 3) & ~0x03;
+ SizeCheck += 12; // 8 + 4 badbeef
+ if ((BulkLength > 1600) ||
+ (SizeCheck > 1600) ||
+ (BulkLength != SizeCheck) ||
+ (BulkLength == 0)) { // Add for fail Urb
+ pWb35Rx->EP3vm_state = VM_STOP;
+ pWb35Rx->Ep3ErrorCount2++;
}
+ }
- // Indicating the receiving data
- pWb35Rx->ByteReceived += BulkLength;
- pWb35Rx->RxBufferSize[ RxBufferId ] = BulkLength;
-
- if (!pWb35Rx->RxOwner[ RxBufferId ])
- Wb35Rx_indicate(pHwData);
+ // Indicating the receiving data
+ pWb35Rx->ByteReceived += BulkLength;
+ pWb35Rx->RxBufferSize[ RxBufferId ] = BulkLength;
- kfree(pWb35Rx->pDRx);
- // Do the next receive
- Wb35Rx(pHwData);
- return;
+ if (!pWb35Rx->RxOwner[ RxBufferId ])
+ Wb35Rx_indicate(pHwData);
- } while(FALSE);
+ kfree(pWb35Rx->pDRx);
+ // Do the next receive
+ Wb35Rx(pHwData);
+ return;
+error:
pWb35Rx->RxOwner[ RxBufferId ] = 1; // Set the owner to hardware
OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Rx->RxFireCounter );
pWb35Rx->EP3vm_state = VM_STOP;
@@ -223,7 +220,7 @@ void Wb35Rx_reset_descriptor( phw_data_t pHwData )
void Wb35Rx_adjust(PDESCRIPTOR pRxDes)
{
- PULONG pRxBufferAddress;
+ u32 * pRxBufferAddress;
u32 DecryptionMethod;
u32 i;
u16 BufferSize;
@@ -264,7 +261,7 @@ u16 Wb35Rx_indicate(phw_data_t pHwData)
{
DESCRIPTOR RxDes;
PWB35RX pWb35Rx = &pHwData->Wb35Rx;
- PUCHAR pRxBufferAddress;
+ u8 * pRxBufferAddress;
u16 PacketSize;
u16 stmp, BufferSize, stmp2 = 0;
u32 RxBufferId;
@@ -283,13 +280,13 @@ u16 Wb35Rx_indicate(phw_data_t pHwData)
// Parse the bulkin buffer
while (BufferSize >= 4) {
- if ((cpu_to_le32(*(PULONG)pRxBufferAddress) & 0x0fffffff) == RX_END_TAG) //Is ending? 921002.9.a
+ if ((cpu_to_le32(*(u32 *)pRxBufferAddress) & 0x0fffffff) == RX_END_TAG) //Is ending? 921002.9.a
break;
// Get the R00 R01 first
- RxDes.R00.value = le32_to_cpu(*(PULONG)pRxBufferAddress);
+ RxDes.R00.value = le32_to_cpu(*(u32 *)pRxBufferAddress);
PacketSize = (u16)RxDes.R00.R00_receive_byte_count;
- RxDes.R01.value = le32_to_cpu(*((PULONG)(pRxBufferAddress+4)));
+ RxDes.R01.value = le32_to_cpu(*((u32 *)(pRxBufferAddress+4)));
// For new DMA 4k
if ((PacketSize & 0x03) > 0)
PacketSize -= 4;
diff --git a/drivers/staging/winbond/linux/wb35rx_s.h b/drivers/staging/winbond/linux/wb35rx_s.h
index 53b831fdeb7..b90c269e6ad 100644
--- a/drivers/staging/winbond/linux/wb35rx_s.h
+++ b/drivers/staging/winbond/linux/wb35rx_s.h
@@ -41,7 +41,7 @@ typedef struct _WB35RX
u32 Ep3ErrorCount2; // 20060625.1 Usbd for Rx DMA error count
int EP3VM_status;
- PUCHAR pDRx;
+ u8 * pDRx;
} WB35RX, *PWB35RX;
diff --git a/drivers/staging/winbond/linux/wb35tx.c b/drivers/staging/winbond/linux/wb35tx.c
index cf19c3bc524..ba9d51244e2 100644
--- a/drivers/staging/winbond/linux/wb35tx.c
+++ b/drivers/staging/winbond/linux/wb35tx.c
@@ -12,7 +12,7 @@
unsigned char
-Wb35Tx_get_tx_buffer(phw_data_t pHwData, PUCHAR *pBuffer )
+Wb35Tx_get_tx_buffer(phw_data_t pHwData, u8 **pBuffer)
{
PWB35TX pWb35Tx = &pHwData->Wb35Tx;
@@ -37,7 +37,7 @@ void Wb35Tx(phw_data_t pHwData)
{
PWB35TX pWb35Tx = &pHwData->Wb35Tx;
PADAPTER Adapter = pHwData->Adapter;
- PUCHAR pTxBufferAddress;
+ u8 *pTxBufferAddress;
PMDS pMds = &Adapter->Mds;
struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb;
int retv;
@@ -100,25 +100,24 @@ void Wb35Tx_complete(struct urb * pUrb)
pWb35Tx->TxSendIndex++;
pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
- do {
- if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
- break;
+ if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
+ goto error;
- if (pWb35Tx->tx_halt)
- break;
+ if (pWb35Tx->tx_halt)
+ goto error;
- // The URB is completed, check the result
- if (pWb35Tx->EP4VM_status != 0) {
- printk("URB submission failed\n");
- pWb35Tx->EP4vm_state = VM_STOP;
- break; // Exit while(FALSE);
- }
+ // The URB is completed, check the result
+ if (pWb35Tx->EP4VM_status != 0) {
+ printk("URB submission failed\n");
+ pWb35Tx->EP4vm_state = VM_STOP;
+ goto error;
+ }
- Mds_Tx(Adapter);
- Wb35Tx(pHwData);
- return;
- } while(FALSE);
+ Mds_Tx(Adapter);
+ Wb35Tx(pHwData);
+ return;
+error:
OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
pWb35Tx->EP4vm_state = VM_STOP;
}
@@ -225,36 +224,33 @@ void Wb35Tx_EP2VM(phw_data_t pHwData)
{
PWB35TX pWb35Tx = &pHwData->Wb35Tx;
struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb;
- PULONG pltmp = (PULONG)pWb35Tx->EP2_buf;
+ u32 * pltmp = (u32 *)pWb35Tx->EP2_buf;
int retv;
- do {
- if (pHwData->SurpriseRemove || pHwData->HwStop)
- break;
-
- if (pWb35Tx->tx_halt)
- break;
-
- //
- // Issuing URB
- //
- usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2),
- pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, pHwData, 32);
+ if (pHwData->SurpriseRemove || pHwData->HwStop)
+ goto error;
- pWb35Tx->EP2vm_state = VM_RUNNING;
- retv = wb_usb_submit_urb( pUrb );
+ if (pWb35Tx->tx_halt)
+ goto error;
- if(retv < 0) {
- #ifdef _PE_TX_DUMP_
- WBDEBUG(("EP2 Tx Irp sending error\n"));
- #endif
- break;
- }
+ //
+ // Issuing URB
+ //
+ usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2),
+ pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, pHwData, 32);
- return;
+ pWb35Tx->EP2vm_state = VM_RUNNING;
+ retv = wb_usb_submit_urb( pUrb );
- } while(FALSE);
+ if (retv < 0) {
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("EP2 Tx Irp sending error\n"));
+ #endif
+ goto error;
+ }
+ return;
+error:
pWb35Tx->EP2vm_state = VM_STOP;
OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
}
@@ -266,7 +262,7 @@ void Wb35Tx_EP2VM_complete(struct urb * pUrb)
T02_DESCRIPTOR T02, TSTATUS;
PADAPTER Adapter = (PADAPTER)pHwData->Adapter;
PWB35TX pWb35Tx = &pHwData->Wb35Tx;
- PULONG pltmp = (PULONG)pWb35Tx->EP2_buf;
+ u32 * pltmp = (u32 *)pWb35Tx->EP2_buf;
u32 i;
u16 InterruptInLength;
@@ -275,38 +271,36 @@ void Wb35Tx_EP2VM_complete(struct urb * pUrb)
pWb35Tx->EP2vm_state = VM_COMPLETED;
pWb35Tx->EP2VM_status = pUrb->status;
- do {
- // For Linux 2.4. Interrupt will always trigger
- if( pHwData->SurpriseRemove || pHwData->HwStop ) // Let WbWlanHalt to handle surprise remove
- break;
-
- if( pWb35Tx->tx_halt )
- break;
-
- //The Urb is completed, check the result
- if (pWb35Tx->EP2VM_status != 0) {
- WBDEBUG(("EP2 IoCompleteRoutine return error\n"));
- pWb35Tx->EP2vm_state= VM_STOP;
- break; // Exit while(FALSE);
- }
-
- // Update the Tx result
- InterruptInLength = pUrb->actual_length;
- // Modify for minimum memory access and DWORD alignment.
- T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
- InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
- InterruptInLength >>= 2; // InterruptInLength/4
- for (i=1; i<=InterruptInLength; i++) {
- T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
-
- TSTATUS.value = T02.value; //20061009 anson's endian
- Mds_SendComplete( Adapter, &TSTATUS );
- T02.value = cpu_to_le32(pltmp[i]) >> 8;
- }
-
- return;
- } while(FALSE);
+ // For Linux 2.4. Interrupt will always trigger
+ if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
+ goto error;
+
+ if (pWb35Tx->tx_halt)
+ goto error;
+
+ //The Urb is completed, check the result
+ if (pWb35Tx->EP2VM_status != 0) {
+ WBDEBUG(("EP2 IoCompleteRoutine return error\n"));
+ pWb35Tx->EP2vm_state= VM_STOP;
+ goto error;
+ }
+ // Update the Tx result
+ InterruptInLength = pUrb->actual_length;
+ // Modify for minimum memory access and DWORD alignment.
+ T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
+ InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
+ InterruptInLength >>= 2; // InterruptInLength/4
+ for (i = 1; i <= InterruptInLength; i++) {
+ T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
+
+ TSTATUS.value = T02.value; //20061009 anson's endian
+ Mds_SendComplete( Adapter, &TSTATUS );
+ T02.value = cpu_to_le32(pltmp[i]) >> 8;
+ }
+
+ return;
+error:
OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
pWb35Tx->EP2vm_state = VM_STOP;
}
diff --git a/drivers/staging/winbond/linux/wb35tx_f.h b/drivers/staging/winbond/linux/wb35tx_f.h
index 7705a8454dc..107b1291813 100644
--- a/drivers/staging/winbond/linux/wb35tx_f.h
+++ b/drivers/staging/winbond/linux/wb35tx_f.h
@@ -3,7 +3,7 @@
//====================================
unsigned char Wb35Tx_initial( phw_data_t pHwData );
void Wb35Tx_destroy( phw_data_t pHwData );
-unsigned char Wb35Tx_get_tx_buffer( phw_data_t pHwData, PUCHAR *pBuffer );
+unsigned char Wb35Tx_get_tx_buffer( phw_data_t pHwData, u8 **pBuffer );
void Wb35Tx_EP2VM( phw_data_t pHwData );
void Wb35Tx_EP2VM_start( phw_data_t pHwData );
diff --git a/drivers/staging/winbond/linux/wbusb.c b/drivers/staging/winbond/linux/wbusb.c
index cbad5fb0595..f4a7875f238 100644
--- a/drivers/staging/winbond/linux/wbusb.c
+++ b/drivers/staging/winbond/linux/wbusb.c
@@ -6,42 +6,29 @@
#include "sysdef.h"
#include <net/mac80211.h>
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
-
-//============================================================
-// vendor ID and product ID can into here for others
-//============================================================
-static struct usb_device_id Id_Table[] =
-{
- {USB_DEVICE( 0x0416, 0x0035 )},
- {USB_DEVICE( 0x18E8, 0x6201 )},
- {USB_DEVICE( 0x18E8, 0x6206 )},
- {USB_DEVICE( 0x18E8, 0x6217 )},
- {USB_DEVICE( 0x18E8, 0x6230 )},
- {USB_DEVICE( 0x18E8, 0x6233 )},
- {USB_DEVICE( 0x1131, 0x2035 )},
- { }
+static struct usb_device_id wb35_table[] __devinitdata = {
+ {USB_DEVICE(0x0416, 0x0035)},
+ {USB_DEVICE(0x18E8, 0x6201)},
+ {USB_DEVICE(0x18E8, 0x6206)},
+ {USB_DEVICE(0x18E8, 0x6217)},
+ {USB_DEVICE(0x18E8, 0x6230)},
+ {USB_DEVICE(0x18E8, 0x6233)},
+ {USB_DEVICE(0x1131, 0x2035)},
+ { 0, }
};
-MODULE_DEVICE_TABLE(usb, Id_Table);
+MODULE_DEVICE_TABLE(usb, wb35_table);
-static struct usb_driver wb35_driver = {
- .name = "w35und",
- .probe = wb35_probe,
- .disconnect = wb35_disconnect,
- .id_table = Id_Table,
-};
-
-static const struct ieee80211_rate wbsoft_rates[] = {
+static struct ieee80211_rate wbsoft_rates[] = {
{ .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
};
-static const struct ieee80211_channel wbsoft_channels[] = {
+static struct ieee80211_channel wbsoft_channels[] = {
{ .center_freq = 2412},
};
@@ -62,9 +49,22 @@ static void wbsoft_remove_interface(struct ieee80211_hw *dev,
printk("wbsoft_remove interface called\n");
}
-static int wbsoft_nop(void)
+static void wbsoft_stop(struct ieee80211_hw *hw)
+{
+ printk(KERN_INFO "%s called\n", __func__);
+}
+
+static int wbsoft_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
{
- printk("wbsoft_nop called\n");
+ printk(KERN_INFO "%s called\n", __func__);
+ return 0;
+}
+
+static int wbsoft_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ printk(KERN_INFO "%s called\n", __func__);
return 0;
}
@@ -105,8 +105,7 @@ static void wbsoft_configure_filter(struct ieee80211_hw *dev,
*total_flags = new_flags;
}
-static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
char *buffer = kmalloc(skb->len, GFP_ATOMIC);
printk("Sending frame %d bytes\n", skb->len);
@@ -136,7 +135,7 @@ static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
hal_set_current_channel(&my_adapter->sHwData, ch);
hal_set_beacon_period(&my_adapter->sHwData, conf->beacon_int);
// hal_set_cap_info(&my_adapter->sHwData, ?? );
-// hal_set_ssid(phw_data_t pHwData, PUCHAR pssid, u8 ssid_len); ??
+// hal_set_ssid(phw_data_t pHwData, u8 * pssid, u8 ssid_len); ??
hal_set_accept_broadcast(&my_adapter->sHwData, 1);
hal_set_accept_promiscuous(&my_adapter->sHwData, 1);
hal_set_accept_multicast(&my_adapter->sHwData, 1);
@@ -148,7 +147,7 @@ static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
// hal_start_bss(&my_adapter->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ??
-//void hal_set_rates(phw_data_t pHwData, PUCHAR pbss_rates,
+//void hal_set_rates(phw_data_t pHwData, u8 * pbss_rates,
// u8 length, unsigned char basic_rate_set)
return 0;
@@ -171,14 +170,14 @@ static u64 wbsoft_get_tsf(struct ieee80211_hw *dev)
static const struct ieee80211_ops wbsoft_ops = {
.tx = wbsoft_tx,
.start = wbsoft_start, /* Start can be pretty much empty as we do WbWLanInitialize() during probe? */
- .stop = wbsoft_nop,
+ .stop = wbsoft_stop,
.add_interface = wbsoft_add_interface,
.remove_interface = wbsoft_remove_interface,
.config = wbsoft_config,
.config_interface = wbsoft_config_interface,
.configure_filter = wbsoft_configure_filter,
- .get_stats = wbsoft_nop,
- .get_tx_stats = wbsoft_nop,
+ .get_stats = wbsoft_get_stats,
+ .get_tx_stats = wbsoft_get_tx_stats,
.get_tsf = wbsoft_get_tsf,
// conf_tx: hal_set_cwmin()/hal_set_cwmax;
};
@@ -187,21 +186,6 @@ struct wbsoft_priv {
};
-int __init wb35_init(void)
-{
- printk("[w35und]driver init\n");
- return usb_register(&wb35_driver);
-}
-
-void __exit wb35_exit(void)
-{
- printk("[w35und]driver exit\n");
- usb_deregister( &wb35_driver );
-}
-
-module_init(wb35_init);
-module_exit(wb35_exit);
-
// Usb kernel subsystem will call this function when a new device is plugged into.
int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table)
{
@@ -210,7 +194,7 @@ int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table)
PWBUSB pWbUsb;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
- int i, ret = -1;
+ int ret = -1;
u32 ltmp;
struct usb_device *udev = interface_to_usbdev(intf);
@@ -218,114 +202,95 @@ int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table)
printk("[w35und]wb35_probe ->\n");
- do {
- for (i=0; i<(sizeof(Id_Table)/sizeof(struct usb_device_id)); i++ ) {
- if ((udev->descriptor.idVendor == Id_Table[i].idVendor) &&
- (udev->descriptor.idProduct == Id_Table[i].idProduct)) {
- printk("[w35und]Found supported hardware\n");
- break;
- }
- }
- if ((i == (sizeof(Id_Table)/sizeof(struct usb_device_id)))) {
- #ifdef _PE_USB_INI_DUMP_
- WBDEBUG(("[w35und] This is not the one we are interested about\n"));
- #endif
- return -ENODEV;
- }
-
- // 20060630.2 Check the device if it already be opened
- ret = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ),
- 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN,
- 0x0, 0x400, &ltmp, 4, HZ*100 );
- if( ret < 0 )
- break;
+ // 20060630.2 Check the device if it already be opened
+ ret = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ),
+ 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN,
+ 0x0, 0x400, &ltmp, 4, HZ*100 );
+ if (ret < 0)
+ goto error;
- ltmp = cpu_to_le32(ltmp);
- if (ltmp) // Is already initialized?
- break;
+ ltmp = cpu_to_le32(ltmp);
+ if (ltmp) // Is already initialized?
+ goto error;
+ Adapter = kzalloc(sizeof(ADAPTER), GFP_KERNEL);
- Adapter = kzalloc(sizeof(ADAPTER), GFP_KERNEL);
+ my_adapter = Adapter;
+ pWbLinux = &Adapter->WbLinux;
+ pWbUsb = &Adapter->sHwData.WbUsb;
+ pWbUsb->udev = udev;
- my_adapter = Adapter;
- pWbLinux = &Adapter->WbLinux;
- pWbUsb = &Adapter->sHwData.WbUsb;
- pWbUsb->udev = udev;
+ interface = intf->cur_altsetting;
+ endpoint = &interface->endpoint[0].desc;
- interface = intf->cur_altsetting;
- endpoint = &interface->endpoint[0].desc;
-
- if (endpoint[2].wMaxPacketSize == 512) {
- printk("[w35und] Working on USB 2.0\n");
- pWbUsb->IsUsb20 = 1;
- }
-
- if (!WbWLanInitialize(Adapter)) {
- printk("[w35und]WbWLanInitialize fail\n");
- break;
- }
+ if (endpoint[2].wMaxPacketSize == 512) {
+ printk("[w35und] Working on USB 2.0\n");
+ pWbUsb->IsUsb20 = 1;
+ }
- {
- struct wbsoft_priv *priv;
- struct ieee80211_hw *dev;
- int res;
+ if (!WbWLanInitialize(Adapter)) {
+ printk("[w35und]WbWLanInitialize fail\n");
+ goto error;
+ }
- dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
+ {
+ struct wbsoft_priv *priv;
+ struct ieee80211_hw *dev;
+ static struct ieee80211_supported_band band;
+ int res;
- if (!dev) {
- printk("w35und: ieee80211 alloc failed\n" );
- BUG();
- }
+ dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
- my_dev = dev;
+ if (!dev) {
+ printk("w35und: ieee80211 alloc failed\n" );
+ BUG();
+ }
- SET_IEEE80211_DEV(dev, &udev->dev);
- {
- phw_data_t pHwData = &Adapter->sHwData;
- unsigned char dev_addr[MAX_ADDR_LEN];
- hal_get_permanent_address(pHwData, dev_addr);
- SET_IEEE80211_PERM_ADDR(dev, dev_addr);
- }
+ my_dev = dev;
+ SET_IEEE80211_DEV(dev, &udev->dev);
+ {
+ phw_data_t pHwData = &Adapter->sHwData;
+ unsigned char dev_addr[MAX_ADDR_LEN];
+ hal_get_permanent_address(pHwData, dev_addr);
+ SET_IEEE80211_PERM_ADDR(dev, dev_addr);
+ }
- dev->extra_tx_headroom = 12; /* FIXME */
- dev->flags = 0;
- dev->channel_change_time = 1000;
-// dev->max_rssi = 100;
+ dev->extra_tx_headroom = 12; /* FIXME */
+ dev->flags = 0;
- dev->queues = 1;
+ dev->channel_change_time = 1000;
+// dev->max_rssi = 100;
- static struct ieee80211_supported_band band;
+ dev->queues = 1;
- band.channels = wbsoft_channels;
- band.n_channels = ARRAY_SIZE(wbsoft_channels);
- band.bitrates = wbsoft_rates;
- band.n_bitrates = ARRAY_SIZE(wbsoft_rates);
+ band.channels = wbsoft_channels;
+ band.n_channels = ARRAY_SIZE(wbsoft_channels);
+ band.bitrates = wbsoft_rates;
+ band.n_bitrates = ARRAY_SIZE(wbsoft_rates);
- dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band;
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band;
#if 0
- wbsoft_modes[0].num_channels = 1;
- wbsoft_modes[0].channels = wbsoft_channels;
- wbsoft_modes[0].mode = MODE_IEEE80211B;
- wbsoft_modes[0].num_rates = ARRAY_SIZE(wbsoft_rates);
- wbsoft_modes[0].rates = wbsoft_rates;
-
- res = ieee80211_register_hwmode(dev, &wbsoft_modes[0]);
- BUG_ON(res);
+ wbsoft_modes[0].num_channels = 1;
+ wbsoft_modes[0].channels = wbsoft_channels;
+ wbsoft_modes[0].mode = MODE_IEEE80211B;
+ wbsoft_modes[0].num_rates = ARRAY_SIZE(wbsoft_rates);
+ wbsoft_modes[0].rates = wbsoft_rates;
+
+ res = ieee80211_register_hwmode(dev, &wbsoft_modes[0]);
+ BUG_ON(res);
#endif
- res = ieee80211_register_hw(dev);
- BUG_ON(res);
- }
-
- usb_set_intfdata( intf, Adapter );
-
- printk("[w35und] _probe OK\n");
- return 0;
+ res = ieee80211_register_hw(dev);
+ BUG_ON(res);
+ }
- } while(FALSE);
+ usb_set_intfdata( intf, Adapter );
+ printk("[w35und] _probe OK\n");
+ return 0;
+error:
return -ENOMEM;
}
@@ -401,4 +366,22 @@ void wb35_disconnect(struct usb_interface *intf)
}
+static struct usb_driver wb35_driver = {
+ .name = "w35und",
+ .id_table = wb35_table,
+ .probe = wb35_probe,
+ .disconnect = wb35_disconnect,
+};
+static int __init wb35_init(void)
+{
+ return usb_register(&wb35_driver);
+}
+
+static void __exit wb35_exit(void)
+{
+ usb_deregister(&wb35_driver);
+}
+
+module_init(wb35_init);
+module_exit(wb35_exit);
diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c
index 8ce6389c413..f1de813f9c7 100644
--- a/drivers/staging/winbond/mds.c
+++ b/drivers/staging/winbond/mds.c
@@ -40,7 +40,7 @@ Mds_Tx(PADAPTER Adapter)
PMDS pMds = &Adapter->Mds;
DESCRIPTOR TxDes;
PDESCRIPTOR pTxDes = &TxDes;
- PUCHAR XmitBufAddress;
+ u8 *XmitBufAddress;
u16 XmitBufSize, PacketSize, stmp, CurrentSize, FragmentThreshold;
u8 FillIndex, TxDesIndex, FragmentCount, FillCount;
unsigned char BufferFilled = FALSE, MICAdd = 0;
@@ -90,7 +90,7 @@ Mds_Tx(PADAPTER Adapter)
BufferFilled = TRUE;
/* Leaves first u8 intact */
- memset((PUCHAR)pTxDes + 1, 0, sizeof(DESCRIPTOR) - 1);
+ memset((u8 *)pTxDes + 1, 0, sizeof(DESCRIPTOR) - 1);
TxDesIndex = pMds->TxDesIndex;//Get the current ID
pTxDes->Descriptor_ID = TxDesIndex;
@@ -229,10 +229,10 @@ Mds_SendComplete(PADAPTER Adapter, PT02_DESCRIPTOR pT02)
}
void
-Mds_HeaderCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
+Mds_HeaderCopy(PADAPTER Adapter, PDESCRIPTOR pDes, u8 *TargetBuffer)
{
PMDS pMds = &Adapter->Mds;
- PUCHAR src_buffer = pDes->buffer_address[0];//931130.5.g
+ u8 *src_buffer = pDes->buffer_address[0];//931130.5.g
PT00_DESCRIPTOR pT00;
PT01_DESCRIPTOR pT01;
u16 stmp;
@@ -276,7 +276,7 @@ Mds_HeaderCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
//
// Set tx rate
//
- stmp = *(PUSHORT)(TargetBuffer+30); // 2n alignment address
+ stmp = *(u16 *)(TargetBuffer+30); // 2n alignment address
//Use basic rate
ctmp1 = ctmpf = CURRENT_TX_RATE_FOR_MNG;
@@ -326,11 +326,13 @@ Mds_HeaderCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
// The function return the 4n size of usb pk
u16
-Mds_BodyCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
+Mds_BodyCopy(PADAPTER Adapter, PDESCRIPTOR pDes, u8 *TargetBuffer)
{
PT00_DESCRIPTOR pT00;
PMDS pMds = &Adapter->Mds;
- PUCHAR buffer, src_buffer, pctmp;
+ u8 *buffer;
+ u8 *src_buffer;
+ u8 *pctmp;
u16 Size = 0;
u16 SizeLeft, CopySize, CopyLeft, stmp;
u8 buf_index, FragmentCount = 0;
@@ -354,7 +356,7 @@ Mds_BodyCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
SizeLeft -= CopySize;
// 1 Byte operation
- pctmp = (PUCHAR)( buffer + 8 + DOT_11_SEQUENCE_OFFSET );
+ pctmp = (u8 *)( buffer + 8 + DOT_11_SEQUENCE_OFFSET );
*pctmp &= 0xf0;
*pctmp |= FragmentCount;//931130.5.m
if( !FragmentCount )
@@ -379,7 +381,7 @@ Mds_BodyCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
buf_index++;
buf_index %= MAX_DESCRIPTOR_BUFFER_INDEX;
} else {
- PUCHAR pctmp = pDes->buffer_address[buf_index];
+ u8 *pctmp = pDes->buffer_address[buf_index];
pctmp += CopySize;
pDes->buffer_address[buf_index] = pctmp;
pDes->buffer_size[buf_index] -= CopySize;
@@ -419,7 +421,7 @@ Mds_BodyCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
pT00->T00_last_mpdu = 1;
pT00->T00_IsLastMpdu = 1;
- buffer = (PUCHAR)pT00 + 8; // +8 for USB hdr
+ buffer = (u8 *)pT00 + 8; // +8 for USB hdr
buffer[1] &= ~0x04; // Clear more frag bit of 802.11 frame control
pDes->FragmentCount = FragmentCount; // Update the correct fragment number
return Size;
@@ -427,7 +429,7 @@ Mds_BodyCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
void
-Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR buffer )
+Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, u8 *buffer )
{
PT00_DESCRIPTOR pT00;
PT01_DESCRIPTOR pT01;
@@ -435,7 +437,7 @@ Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR buffer )
u8 Rate, i;
unsigned char CTS_on = FALSE, RTS_on = FALSE;
PT00_DESCRIPTOR pNextT00;
- u16 BodyLen;
+ u16 BodyLen = 0;
unsigned char boGroupAddr = FALSE;
@@ -574,7 +576,7 @@ Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR buffer )
DEFAULT_SIFSTIME*3 );
}
- ((PUSHORT)buffer)[5] = cpu_to_le16(Duration);// 4 USHOR for skip 8B USB, 2USHORT=FC + Duration
+ ((u16 *)buffer)[5] = cpu_to_le16(Duration);// 4 USHOR for skip 8B USB, 2USHORT=FC + Duration
//----20061009 add by anson's endian
pNextT00->value = cpu_to_le32(pNextT00->value);
@@ -615,7 +617,7 @@ Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR buffer )
}
}
- ((PUSHORT)buffer)[5] = cpu_to_le16(Duration);// 4 USHOR for skip 8B USB, 2USHORT=FC + Duration
+ ((u16 *)buffer)[5] = cpu_to_le16(Duration);// 4 USHOR for skip 8B USB, 2USHORT=FC + Duration
pT00->value = cpu_to_le32(pT00->value);
pT01->value = cpu_to_le32(pT01->value);
//--end 20061009 add
diff --git a/drivers/staging/winbond/mds_f.h b/drivers/staging/winbond/mds_f.h
index 651188be106..7a682d4cfbd 100644
--- a/drivers/staging/winbond/mds_f.h
+++ b/drivers/staging/winbond/mds_f.h
@@ -1,9 +1,9 @@
unsigned char Mds_initial( PADAPTER Adapter );
void Mds_Destroy( PADAPTER Adapter );
void Mds_Tx( PADAPTER Adapter );
-void Mds_HeaderCopy( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer );
-u16 Mds_BodyCopy( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer );
-void Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer );
+void Mds_HeaderCopy( PADAPTER Adapter, PDESCRIPTOR pDes, u8 *TargetBuffer );
+u16 Mds_BodyCopy( PADAPTER Adapter, PDESCRIPTOR pDes, u8 *TargetBuffer );
+void Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, u8 *TargetBuffer );
void Mds_SendComplete( PADAPTER Adapter, PT02_DESCRIPTOR pT02 );
void Mds_MpduProcess( PADAPTER Adapter, PDESCRIPTOR pRxDes );
void Mds_reset_descriptor( PADAPTER Adapter );
diff --git a/drivers/staging/winbond/mds_s.h b/drivers/staging/winbond/mds_s.h
index 4738279d5f3..9df2e0936bf 100644
--- a/drivers/staging/winbond/mds_s.h
+++ b/drivers/staging/winbond/mds_s.h
@@ -86,7 +86,7 @@ typedef struct _MDS
{
// For Tx usage
u8 TxOwner[ ((MAX_USB_TX_BUFFER_NUMBER + 3) & ~0x03) ];
- PUCHAR pTxBuffer;
+ u8 *pTxBuffer;
u16 TxBufferSize[ ((MAX_USB_TX_BUFFER_NUMBER + 1) & ~0x01) ];
u8 TxDesFrom[ ((MAX_USB_TX_DESCRIPTOR + 3) & ~0x03) ];//931130.4.u // 1: MLME 2: NDIS control 3: NDIS data
u8 TxCountInBuffer[ ((MAX_USB_TX_DESCRIPTOR + 3) & ~0x03) ]; // 20060928
@@ -103,7 +103,7 @@ typedef struct _MDS
u16 TxResult[ ((MAX_USB_TX_DESCRIPTOR + 1) & ~0x01) ];//Collect the sending result of Mpdu
u8 MicRedundant[8]; // For tmp use
- PUCHAR MicWriteAddress[2]; //The start address to fill the Mic, use 2 point due to Mic maybe fragment
+ u8 *MicWriteAddress[2]; //The start address to fill the Mic, use 2 point due to Mic maybe fragment
u16 MicWriteSize[2]; //931130.4.x
@@ -144,7 +144,7 @@ typedef struct _MDS
typedef struct _RxBuffer
{
- PUCHAR pBufferAddress; // Pointer the received data buffer.
+ u8 * pBufferAddress; // Pointer the received data buffer.
u16 BufferSize;
u8 RESERVED;
u8 BufferIndex;// Only 1 byte
@@ -176,7 +176,7 @@ typedef struct _RXLAYER1
/////////////////////////////////////////////////////////////////////////////////////////////
// For brand-new Rx system
u8 ReservedBuffer[ 2400 ];//If Buffer ID is reserved one, it must copy the data into this area
- PUCHAR ReservedBufferPoint;// Point to the next availabe address of reserved buffer
+ u8 *ReservedBufferPoint;// Point to the next availabe address of reserved buffer
}RXLAYER1, * PRXLAYER1;
diff --git a/drivers/staging/winbond/mlme_s.h b/drivers/staging/winbond/mlme_s.h
index 58094f61c03..039fd408ba6 100644
--- a/drivers/staging/winbond/mlme_s.h
+++ b/drivers/staging/winbond/mlme_s.h
@@ -125,12 +125,12 @@
typedef struct _MLME_FRAME
{
//NDIS_PACKET MLME_Packet;
- PCHAR pMMPDU;
+ s8 * pMMPDU;
u16 len;
u8 DataType;
u8 IsInUsed;
- OS_SPIN_LOCK MLMESpinLock;
+ spinlock_t MLMESpinLock;
u8 TxMMPDU[MAX_NUM_TX_MMPDU][MAX_MMPDU_SIZE];
u8 TxMMPDUInUse[ (MAX_NUM_TX_MMPDU+3) & ~0x03 ];
diff --git a/drivers/staging/winbond/mlmetxrx.c b/drivers/staging/winbond/mlmetxrx.c
index 46b091e9679..e8533b8d197 100644
--- a/drivers/staging/winbond/mlmetxrx.c
+++ b/drivers/staging/winbond/mlmetxrx.c
@@ -113,13 +113,13 @@ MLME_GetNextPacket(PADAPTER Adapter, PDESCRIPTOR pDes)
pDes->Type = Adapter->sMlmeFrame.DataType;
}
-void MLMEfreeMMPDUBuffer(PWB32_ADAPTER Adapter, PCHAR pData)
+void MLMEfreeMMPDUBuffer(PWB32_ADAPTER Adapter, s8 *pData)
{
int i;
// Reclaim the data buffer
for (i = 0; i < MAX_NUM_TX_MMPDU; i++) {
- if (pData == (PCHAR)&(Adapter->sMlmeFrame.TxMMPDU[i]))
+ if (pData == (s8 *)&(Adapter->sMlmeFrame.TxMMPDU[i]))
break;
}
if (Adapter->sMlmeFrame.TxMMPDUInUse[i])
diff --git a/drivers/staging/winbond/mlmetxrx_f.h b/drivers/staging/winbond/mlmetxrx_f.h
index d74e225be21..24cd5f308d9 100644
--- a/drivers/staging/winbond/mlmetxrx_f.h
+++ b/drivers/staging/winbond/mlmetxrx_f.h
@@ -20,7 +20,7 @@ MLMEGetMMPDUBuffer(
PWB32_ADAPTER Adapter
);
-void MLMEfreeMMPDUBuffer( PWB32_ADAPTER Adapter, PCHAR pData);
+void MLMEfreeMMPDUBuffer( PWB32_ADAPTER Adapter, s8 * pData);
void MLME_GetNextPacket( PADAPTER Adapter, PDESCRIPTOR pDes );
u8 MLMESendFrame( PWB32_ADAPTER Adapter,
@@ -42,7 +42,7 @@ MLMERcvFrame(
void
MLMEReturnPacket(
PWB32_ADAPTER Adapter,
- PUCHAR pRxBufer
+ u8 * pRxBufer
);
#ifdef _IBSS_BEACON_SEQ_STICK_
s8 SendBCNullData(PWB32_ADAPTER Adapter, u16 wIdx);
diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c
index b475c7a7c42..57af5b83150 100644
--- a/drivers/staging/winbond/reg.c
+++ b/drivers/staging/winbond/reg.c
@@ -922,16 +922,16 @@ Uxx_ReadEthernetAddress( phw_data_t pHwData )
// Only unplug and plug again can make hardware read EEPROM again. 20060727
Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08000000 ); // Start EEPROM access + Read + address(0x0d)
Wb35Reg_ReadSync( pHwData, 0x03b4, &ltmp );
- *(PUSHORT)pHwData->PermanentMacAddress = cpu_to_le16((u16)ltmp); //20060926 anson's endian
+ *(u16 *)pHwData->PermanentMacAddress = cpu_to_le16((u16)ltmp); //20060926 anson's endian
Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08010000 ); // Start EEPROM access + Read + address(0x0d)
Wb35Reg_ReadSync( pHwData, 0x03b4, &ltmp );
- *(PUSHORT)(pHwData->PermanentMacAddress + 2) = cpu_to_le16((u16)ltmp); //20060926 anson's endian
+ *(u16 *)(pHwData->PermanentMacAddress + 2) = cpu_to_le16((u16)ltmp); //20060926 anson's endian
Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08020000 ); // Start EEPROM access + Read + address(0x0d)
Wb35Reg_ReadSync( pHwData, 0x03b4, &ltmp );
- *(PUSHORT)(pHwData->PermanentMacAddress + 4) = cpu_to_le16((u16)ltmp); //20060926 anson's endian
- *(PUSHORT)(pHwData->PermanentMacAddress + 6) = 0;
- Wb35Reg_WriteSync( pHwData, 0x03e8, cpu_to_le32(*(PULONG)pHwData->PermanentMacAddress) ); //20060926 anson's endian
- Wb35Reg_WriteSync( pHwData, 0x03ec, cpu_to_le32(*(PULONG)(pHwData->PermanentMacAddress+4)) ); //20060926 anson's endian
+ *(u16 *)(pHwData->PermanentMacAddress + 4) = cpu_to_le16((u16)ltmp); //20060926 anson's endian
+ *(u16 *)(pHwData->PermanentMacAddress + 6) = 0;
+ Wb35Reg_WriteSync( pHwData, 0x03e8, cpu_to_le32(*(u32 *)pHwData->PermanentMacAddress) ); //20060926 anson's endian
+ Wb35Reg_WriteSync( pHwData, 0x03ec, cpu_to_le32(*(u32 *)(pHwData->PermanentMacAddress+4)) ); //20060926 anson's endian
}
@@ -1038,7 +1038,7 @@ void
RFSynthesizer_initial(phw_data_t pHwData)
{
u32 altmp[32];
- PULONG pltmp = altmp;
+ u32 * pltmp = altmp;
u32 ltmp;
u8 number=0x00; // The number of register vale
u8 i;
@@ -2358,11 +2358,11 @@ void Mxx_initial( phw_data_t pHwData )
pltmp[2] = pWb35Reg->M2C_MacControl;
// M30 BSSID
- pltmp[3] = *(PULONG)pHwData->bssid;
+ pltmp[3] = *(u32 *)pHwData->bssid;
// M34
pHwData->AID = DEFAULT_AID;
- tmp = *(PUSHORT)(pHwData->bssid+4);
+ tmp = *(u16 *)(pHwData->bssid+4);
tmp |= DEFAULT_AID << 16;
pltmp[4] = tmp;
@@ -2428,7 +2428,7 @@ void GetTxVgaFromEEPROM( phw_data_t pHwData )
{
u32 i, j, ltmp;
u16 Value[MAX_TXVGA_EEPROM];
- PUCHAR pctmp;
+ u8 *pctmp;
u8 ctmp=0;
// Get the entire TxVga setting in EEPROM
@@ -2441,7 +2441,7 @@ void GetTxVgaFromEEPROM( phw_data_t pHwData )
}
// Adjust the filed which fills with reserved value.
- pctmp = (PUCHAR)Value;
+ pctmp = (u8 *)Value;
for( i=0; i<(MAX_TXVGA_EEPROM*2); i++ )
{
if( pctmp[i] != 0xff )
@@ -2480,7 +2480,7 @@ void GetTxVgaFromEEPROM( phw_data_t pHwData )
// This function will use default TxVgaSettingInEEPROM data to calculate new TxVga.
void EEPROMTxVgaAdjust( phw_data_t pHwData ) // 20060619.5 Add
{
- PUCHAR pTxVga = pHwData->TxVgaSettingInEEPROM;
+ u8 * pTxVga = pHwData->TxVgaSettingInEEPROM;
s16 i, stmp;
//-- 2.4G -- 20060704.2 Request from Tiger
diff --git a/drivers/staging/winbond/sme_api.c b/drivers/staging/winbond/sme_api.c
index 40e93b7600e..31c9673ea86 100644
--- a/drivers/staging/winbond/sme_api.c
+++ b/drivers/staging/winbond/sme_api.c
@@ -10,4 +10,5 @@
s8 sme_get_rssi(void *pcore_data, s32 *prssi)
{
BUG();
+ return 0;
}
diff --git a/drivers/staging/winbond/sme_api.h b/drivers/staging/winbond/sme_api.h
index 016b225ca4a..745eb376bc7 100644
--- a/drivers/staging/winbond/sme_api.h
+++ b/drivers/staging/winbond/sme_api.h
@@ -208,7 +208,7 @@ s8 sme_set_tx_antenna(void *pcore_data, u32 TxAntenna);
s8 sme_set_IBSS_chan(void *pcore_data, ChanInfo chan);
//20061108 WPS
-s8 sme_set_IE_append(void *pcore_data, PUCHAR buffer, u16 buf_len);
+s8 sme_set_IE_append(void *pcore_data, u8 *buffer, u16 buf_len);
diff --git a/drivers/staging/winbond/wbhal.c b/drivers/staging/winbond/wbhal.c
index daf44224755..5d68ecec34c 100644
--- a/drivers/staging/winbond/wbhal.c
+++ b/drivers/staging/winbond/wbhal.c
@@ -1,13 +1,13 @@
#include "os_common.h"
-void hal_get_ethernet_address( phw_data_t pHwData, PUCHAR current_address )
+void hal_get_ethernet_address( phw_data_t pHwData, u8 *current_address )
{
if( pHwData->SurpriseRemove ) return;
memcpy( current_address, pHwData->CurrentMacAddress, ETH_LENGTH_OF_ADDRESS );
}
-void hal_set_ethernet_address( phw_data_t pHwData, PUCHAR current_address )
+void hal_set_ethernet_address( phw_data_t pHwData, u8 *current_address )
{
u32 ltmp[2];
@@ -15,13 +15,13 @@ void hal_set_ethernet_address( phw_data_t pHwData, PUCHAR current_address )
memcpy( pHwData->CurrentMacAddress, current_address, ETH_LENGTH_OF_ADDRESS );
- ltmp[0]= cpu_to_le32( *(PULONG)pHwData->CurrentMacAddress );
- ltmp[1]= cpu_to_le32( *(PULONG)(pHwData->CurrentMacAddress + 4) ) & 0xffff;
+ ltmp[0]= cpu_to_le32( *(u32 *)pHwData->CurrentMacAddress );
+ ltmp[1]= cpu_to_le32( *(u32 *)(pHwData->CurrentMacAddress + 4) ) & 0xffff;
Wb35Reg_BurstWrite( pHwData, 0x03e8, ltmp, 2, AUTO_INCREMENT );
}
-void hal_get_permanent_address( phw_data_t pHwData, PUCHAR pethernet_address )
+void hal_get_permanent_address( phw_data_t pHwData, u8 *pethernet_address )
{
if( pHwData->SurpriseRemove ) return;
@@ -89,7 +89,7 @@ void hal_halt(phw_data_t pHwData, void *ppa_data)
}
//---------------------------------------------------------------------------------------------------
-void hal_set_rates(phw_data_t pHwData, PUCHAR pbss_rates,
+void hal_set_rates(phw_data_t pHwData, u8 *pbss_rates,
u8 length, unsigned char basic_rate_set)
{
PWB35REG pWb35Reg = &pHwData->Wb35Reg;
@@ -158,13 +158,13 @@ void hal_set_rates(phw_data_t pHwData, PUCHAR pbss_rates,
// Fill data into support rate until buffer full
//---20060926 add by anson's endian
for (i=0; i<4; i++)
- *(PULONG)(SupportedRate+(i<<2)) = cpu_to_le32( *(PULONG)(SupportedRate+(i<<2)) );
+ *(u32 *)(SupportedRate+(i<<2)) = cpu_to_le32( *(u32 *)(SupportedRate+(i<<2)) );
//--- end 20060926 add by anson's endian
- Wb35Reg_BurstWrite( pHwData,0x087c, (PULONG)SupportedRate, 4, AUTO_INCREMENT );
- pWb35Reg->M7C_MacControl = ((PULONG)SupportedRate)[0];
- pWb35Reg->M80_MacControl = ((PULONG)SupportedRate)[1];
- pWb35Reg->M84_MacControl = ((PULONG)SupportedRate)[2];
- pWb35Reg->M88_MacControl = ((PULONG)SupportedRate)[3];
+ Wb35Reg_BurstWrite( pHwData,0x087c, (u32 *)SupportedRate, 4, AUTO_INCREMENT );
+ pWb35Reg->M7C_MacControl = ((u32 *)SupportedRate)[0];
+ pWb35Reg->M80_MacControl = ((u32 *)SupportedRate)[1];
+ pWb35Reg->M84_MacControl = ((u32 *)SupportedRate)[2];
+ pWb35Reg->M88_MacControl = ((u32 *)SupportedRate)[3];
// Fill length
tmp = Count1<<28 | Count2<<24;
@@ -206,7 +206,7 @@ void hal_set_current_channel_ex( phw_data_t pHwData, ChanInfo channel )
pWb35Reg->M28_MacControl &= ~0xff; // Clean channel information field
pWb35Reg->M28_MacControl |= channel.ChanNo;
Wb35Reg_WriteWithCallbackValue( pHwData, 0x0828, pWb35Reg->M28_MacControl,
- (PCHAR)&channel, sizeof(ChanInfo));
+ (s8 *)&channel, sizeof(ChanInfo));
}
//---------------------------------------------------------------------------------------------------
void hal_set_current_channel( phw_data_t pHwData, ChanInfo channel )
@@ -277,7 +277,7 @@ void hal_set_accept_beacon( phw_data_t pHwData, u8 enable )
Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl );
}
//---------------------------------------------------------------------------------------------------
-void hal_set_multicast_address( phw_data_t pHwData, PUCHAR address, u8 number )
+void hal_set_multicast_address( phw_data_t pHwData, u8 *address, u8 number )
{
PWB35REG pWb35Reg = &pHwData->Wb35Reg;
u8 Byte, Bit;
@@ -297,7 +297,7 @@ void hal_set_multicast_address( phw_data_t pHwData, PUCHAR address, u8 number )
}
// Updating register
- Wb35Reg_BurstWrite( pHwData, 0x0804, (PULONG)pWb35Reg->Multicast, 2, AUTO_INCREMENT );
+ Wb35Reg_BurstWrite( pHwData, 0x0804, (u32 *)pWb35Reg->Multicast, 2, AUTO_INCREMENT );
}
//---------------------------------------------------------------------------------------------------
u8 hal_get_accept_beacon( phw_data_t pHwData )
@@ -806,7 +806,7 @@ u8 hal_get_hw_radio_off( phw_data_t pHwData )
}
}
-unsigned char hal_get_dxx_reg( phw_data_t pHwData, u16 number, PULONG pValue )
+unsigned char hal_get_dxx_reg( phw_data_t pHwData, u16 number, u32 * pValue )
{
if( number < 0x1000 )
number += 0x1000;
diff --git a/drivers/staging/winbond/wbhal_f.h b/drivers/staging/winbond/wbhal_f.h
index fe25f97af72..ea9531ac847 100644
--- a/drivers/staging/winbond/wbhal_f.h
+++ b/drivers/staging/winbond/wbhal_f.h
@@ -16,23 +16,23 @@
//====================================================================================
// Function declaration
//====================================================================================
-void hal_remove_mapping_key( phw_data_t pHwData, PUCHAR pmac_addr );
+void hal_remove_mapping_key( phw_data_t pHwData, u8 *pmac_addr );
void hal_remove_default_key( phw_data_t pHwData, u32 index );
-unsigned char hal_set_mapping_key( phw_data_t Adapter, PUCHAR pmac_addr, u8 null_key, u8 wep_on, PUCHAR ptx_tsc, PUCHAR prx_tsc, u8 key_type, u8 key_len, PUCHAR pkey_data );
-unsigned char hal_set_default_key( phw_data_t Adapter, u8 index, u8 null_key, u8 wep_on, PUCHAR ptx_tsc, PUCHAR prx_tsc, u8 key_type, u8 key_len, PUCHAR pkey_data );
+unsigned char hal_set_mapping_key( phw_data_t Adapter, u8 *pmac_addr, u8 null_key, u8 wep_on, u8 *ptx_tsc, u8 *prx_tsc, u8 key_type, u8 key_len, u8 *pkey_data );
+unsigned char hal_set_default_key( phw_data_t Adapter, u8 index, u8 null_key, u8 wep_on, u8 *ptx_tsc, u8 *prx_tsc, u8 key_type, u8 key_len, u8 *pkey_data );
void hal_clear_all_default_key( phw_data_t pHwData );
void hal_clear_all_group_key( phw_data_t pHwData );
void hal_clear_all_mapping_key( phw_data_t pHwData );
void hal_clear_all_key( phw_data_t pHwData );
-void hal_get_ethernet_address( phw_data_t pHwData, PUCHAR current_address );
-void hal_set_ethernet_address( phw_data_t pHwData, PUCHAR current_address );
-void hal_get_permanent_address( phw_data_t pHwData, PUCHAR pethernet_address );
+void hal_get_ethernet_address( phw_data_t pHwData, u8 *current_address );
+void hal_set_ethernet_address( phw_data_t pHwData, u8 *current_address );
+void hal_get_permanent_address( phw_data_t pHwData, u8 *pethernet_address );
unsigned char hal_init_hardware( phw_data_t pHwData, PADAPTER Adapter );
void hal_set_power_save_mode( phw_data_t pHwData, unsigned char power_save, unsigned char wakeup, unsigned char dtim );
-void hal_get_power_save_mode( phw_data_t pHwData, PBOOLEAN pin_pwr_save );
+void hal_get_power_save_mode( phw_data_t pHwData, u8 *pin_pwr_save );
void hal_set_slot_time( phw_data_t pHwData, u8 type );
#define hal_set_atim_window( _A, _ATM )
-void hal_set_rates( phw_data_t pHwData, PUCHAR pbss_rates, u8 length, unsigned char basic_rate_set );
+void hal_set_rates( phw_data_t pHwData, u8 *pbss_rates, u8 length, unsigned char basic_rate_set );
#define hal_set_basic_rates( _A, _R, _L ) hal_set_rates( _A, _R, _L, TRUE )
#define hal_set_op_rates( _A, _R, _L ) hal_set_rates( _A, _R, _L, FALSE )
void hal_start_bss( phw_data_t pHwData, u8 mac_op_mode );
@@ -40,19 +40,19 @@ void hal_join_request( phw_data_t pHwData, u8 bss_type ); // 0:BSS STA 1:IBSS
void hal_stop_sync_bss( phw_data_t pHwData );
void hal_resume_sync_bss( phw_data_t pHwData);
void hal_set_aid( phw_data_t pHwData, u16 aid );
-void hal_set_bssid( phw_data_t pHwData, PUCHAR pbssid );
-void hal_get_bssid( phw_data_t pHwData, PUCHAR pbssid );
+void hal_set_bssid( phw_data_t pHwData, u8 *pbssid );
+void hal_get_bssid( phw_data_t pHwData, u8 *pbssid );
void hal_set_beacon_period( phw_data_t pHwData, u16 beacon_period );
void hal_set_listen_interval( phw_data_t pHwData, u16 listen_interval );
void hal_set_cap_info( phw_data_t pHwData, u16 capability_info );
-void hal_set_ssid( phw_data_t pHwData, PUCHAR pssid, u8 ssid_len );
+void hal_set_ssid( phw_data_t pHwData, u8 *pssid, u8 ssid_len );
void hal_set_current_channel( phw_data_t pHwData, ChanInfo channel );
void hal_set_current_channel_ex( phw_data_t pHwData, ChanInfo channel );
void hal_get_current_channel( phw_data_t pHwData, ChanInfo *channel );
void hal_set_accept_broadcast( phw_data_t pHwData, u8 enable );
void hal_set_accept_multicast( phw_data_t pHwData, u8 enable );
void hal_set_accept_beacon( phw_data_t pHwData, u8 enable );
-void hal_set_multicast_address( phw_data_t pHwData, PUCHAR address, u8 number );
+void hal_set_multicast_address( phw_data_t pHwData, u8 *address, u8 number );
u8 hal_get_accept_beacon( phw_data_t pHwData );
void hal_stop( phw_data_t pHwData );
void hal_halt( phw_data_t pHwData, void *ppa_data );
@@ -97,7 +97,7 @@ void hal_surprise_remove( phw_data_t pHwData );
void hal_rate_change( phw_data_t pHwData ); // Notify the HAL rate is changing 20060613.1
-unsigned char hal_get_dxx_reg( phw_data_t pHwData, u16 number, PULONG pValue );
+unsigned char hal_get_dxx_reg( phw_data_t pHwData, u16 number, u32 * pValue );
unsigned char hal_set_dxx_reg( phw_data_t pHwData, u16 number, u32 value );
#define hal_get_time_count( _P ) (_P->time_count/10) // return 100ms count
#define hal_detect_error( _P ) (_P->WbUsb.DetectCount)
@@ -116,7 +116,7 @@ unsigned char hal_idle( phw_data_t pHwData );
#define pa_stall_execution( _A ) //OS_SLEEP( 1 )
#define hw_get_cxx_reg( _A, _B, _C )
#define hw_set_cxx_reg( _A, _B, _C )
-#define hw_get_dxx_reg( _A, _B, _C ) hal_get_dxx_reg( _A, _B, (PULONG)_C )
+#define hw_get_dxx_reg( _A, _B, _C ) hal_get_dxx_reg( _A, _B, (u32 *)_C )
#define hw_set_dxx_reg( _A, _B, _C ) hal_set_dxx_reg( _A, _B, (u32)_C )
diff --git a/drivers/staging/winbond/wbhal_s.h b/drivers/staging/winbond/wbhal_s.h
index 5b862ff357b..2ee3f0fc1ad 100644
--- a/drivers/staging/winbond/wbhal_s.h
+++ b/drivers/staging/winbond/wbhal_s.h
@@ -461,7 +461,7 @@ typedef struct _HW_DATA_T
//=====================================================================
// Definition for 802.11
//=====================================================================
- PUCHAR bssid_pointer; // Used by hal_get_bssid for return value
+ u8 *bssid_pointer; // Used by hal_get_bssid for return value
u8 bssid[8];// Only 6 byte will be used. 8 byte is required for read buffer
u8 ssid[32];// maximum ssid length is 32 byte
@@ -486,7 +486,7 @@ typedef struct _HW_DATA_T
u32 CurrentRadioSw; // 20060320.2 0:On 1:Off
u32 CurrentRadioHw; // 20060825 0:On 1:Off
- PUCHAR power_save_point; // Used by hal_get_power_save_mode for return value
+ u8 *power_save_point; // Used by hal_get_power_save_mode for return value
u8 cwmin;
u8 desired_power_save;
u8 dtim;// Is running dtim
diff --git a/drivers/staging/winbond/wblinux.c b/drivers/staging/winbond/wblinux.c
index 2eade5a47b1..4ed45e48831 100644
--- a/drivers/staging/winbond/wblinux.c
+++ b/drivers/staging/winbond/wblinux.c
@@ -25,11 +25,11 @@ EncapAtomicInc(PADAPTER Adapter, void* pAtomic)
{
PWBLINUX pWbLinux = &Adapter->WbLinux;
u32 ltmp;
- PULONG pltmp = (PULONG)pAtomic;
- OS_SPIN_LOCK_ACQUIRED( &pWbLinux->AtomicSpinLock );
+ u32 * pltmp = (u32 *)pAtomic;
+ spin_lock_irq( &pWbLinux->AtomicSpinLock );
(*pltmp)++;
ltmp = (*pltmp);
- OS_SPIN_LOCK_RELEASED( &pWbLinux->AtomicSpinLock );
+ spin_unlock_irq( &pWbLinux->AtomicSpinLock );
return ltmp;
}
@@ -38,11 +38,11 @@ EncapAtomicDec(PADAPTER Adapter, void* pAtomic)
{
PWBLINUX pWbLinux = &Adapter->WbLinux;
u32 ltmp;
- PULONG pltmp = (PULONG)pAtomic;
- OS_SPIN_LOCK_ACQUIRED( &pWbLinux->AtomicSpinLock );
+ u32 * pltmp = (u32 *)pAtomic;
+ spin_lock_irq( &pWbLinux->AtomicSpinLock );
(*pltmp)--;
ltmp = (*pltmp);
- OS_SPIN_LOCK_RELEASED( &pWbLinux->AtomicSpinLock );
+ spin_unlock_irq( &pWbLinux->AtomicSpinLock );
return ltmp;
}
@@ -51,8 +51,8 @@ WBLINUX_Initial(PADAPTER Adapter)
{
PWBLINUX pWbLinux = &Adapter->WbLinux;
- OS_SPIN_LOCK_ALLOCATE( &pWbLinux->SpinLock );
- OS_SPIN_LOCK_ALLOCATE( &pWbLinux->AtomicSpinLock );
+ spin_lock_init( &pWbLinux->SpinLock );
+ spin_lock_init( &pWbLinux->AtomicSpinLock );
return TRUE;
}
@@ -79,7 +79,6 @@ void
WBLINUX_Destroy(PADAPTER Adapter)
{
WBLINUX_stop( Adapter );
- OS_SPIN_LOCK_FREE( &pWbNdis->SpinLock );
#ifdef _PE_USB_INI_DUMP_
WBDEBUG(("[w35und] unregister_netdev!\n"));
#endif
@@ -142,119 +141,118 @@ unsigned char
WbWLanInitialize(PADAPTER Adapter)
{
phw_data_t pHwData;
- PUCHAR pMacAddr, pMacAddr2;
+ u8 *pMacAddr;
+ u8 *pMacAddr2;
u32 InitStep = 0;
u8 EEPROM_region;
u8 HwRadioOff;
- do {
- //
- // Setting default value for Linux
- //
- Adapter->sLocalPara.region_INF = REGION_AUTO;
- Adapter->sLocalPara.TxRateMode = RATE_AUTO;
- psLOCAL->bMacOperationMode = MODE_802_11_BG; // B/G mode
- Adapter->Mds.TxRTSThreshold = DEFAULT_RTSThreshold;
- Adapter->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
- hal_set_phy_type( &Adapter->sHwData, RF_WB_242_1 );
- Adapter->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE;
- psLOCAL->bPreambleMode = AUTO_MODE;
- Adapter->sLocalPara.RadioOffStatus.boSwRadioOff = FALSE;
- pHwData = &Adapter->sHwData;
- hal_set_phy_type( pHwData, RF_DECIDE_BY_INF );
-
- //
- // Initial each module and variable
- //
- if (!WBLINUX_Initial(Adapter)) {
+ //
+ // Setting default value for Linux
+ //
+ Adapter->sLocalPara.region_INF = REGION_AUTO;
+ Adapter->sLocalPara.TxRateMode = RATE_AUTO;
+ psLOCAL->bMacOperationMode = MODE_802_11_BG; // B/G mode
+ Adapter->Mds.TxRTSThreshold = DEFAULT_RTSThreshold;
+ Adapter->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
+ hal_set_phy_type( &Adapter->sHwData, RF_WB_242_1 );
+ Adapter->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE;
+ psLOCAL->bPreambleMode = AUTO_MODE;
+ Adapter->sLocalPara.RadioOffStatus.boSwRadioOff = FALSE;
+ pHwData = &Adapter->sHwData;
+ hal_set_phy_type( pHwData, RF_DECIDE_BY_INF );
+
+ //
+ // Initial each module and variable
+ //
+ if (!WBLINUX_Initial(Adapter)) {
#ifdef _PE_USB_INI_DUMP_
- WBDEBUG(("[w35und]WBNDIS initialization failed\n"));
+ WBDEBUG(("[w35und]WBNDIS initialization failed\n"));
#endif
- break;
- }
+ goto error;
+ }
- // Initial Software variable
- Adapter->sLocalPara.ShutDowned = FALSE;
-
- //added by ws for wep key error detection
- Adapter->sLocalPara.bWepKeyError= FALSE;
- Adapter->sLocalPara.bToSelfPacketReceived = FALSE;
- Adapter->sLocalPara.WepKeyDetectTimerCount= 2 * 100; /// 2 seconds
-
- // Initial USB hal
- InitStep = 1;
- pHwData = &Adapter->sHwData;
- if (!hal_init_hardware(pHwData, Adapter))
- break;
-
- EEPROM_region = hal_get_region_from_EEPROM( pHwData );
- if (EEPROM_region != REGION_AUTO)
- psLOCAL->region = EEPROM_region;
- else {
- if (psLOCAL->region_INF != REGION_AUTO)
- psLOCAL->region = psLOCAL->region_INF;
- else
- psLOCAL->region = REGION_USA; //default setting
- }
+ // Initial Software variable
+ Adapter->sLocalPara.ShutDowned = FALSE;
+
+ //added by ws for wep key error detection
+ Adapter->sLocalPara.bWepKeyError= FALSE;
+ Adapter->sLocalPara.bToSelfPacketReceived = FALSE;
+ Adapter->sLocalPara.WepKeyDetectTimerCount= 2 * 100; /// 2 seconds
+
+ // Initial USB hal
+ InitStep = 1;
+ pHwData = &Adapter->sHwData;
+ if (!hal_init_hardware(pHwData, Adapter))
+ goto error;
+
+ EEPROM_region = hal_get_region_from_EEPROM( pHwData );
+ if (EEPROM_region != REGION_AUTO)
+ psLOCAL->region = EEPROM_region;
+ else {
+ if (psLOCAL->region_INF != REGION_AUTO)
+ psLOCAL->region = psLOCAL->region_INF;
+ else
+ psLOCAL->region = REGION_USA; //default setting
+ }
- // Get Software setting flag from hal
- Adapter->sLocalPara.boAntennaDiversity = FALSE;
- if (hal_software_set(pHwData) & 0x00000001)
- Adapter->sLocalPara.boAntennaDiversity = TRUE;
-
- //
- // For TS module
- //
- InitStep = 2;
-
- // For MDS module
- InitStep = 3;
- Mds_initial(Adapter);
-
- //=======================================
- // Initialize the SME, SCAN, MLME, ROAM
- //=======================================
- InitStep = 4;
- InitStep = 5;
- InitStep = 6;
-
- // If no user-defined address in the registry, use the addresss "burned" on the NIC instead.
- pMacAddr = Adapter->sLocalPara.ThisMacAddress;
- pMacAddr2 = Adapter->sLocalPara.PermanentAddress;
- hal_get_permanent_address( pHwData, Adapter->sLocalPara.PermanentAddress );// Reading ethernet address from EEPROM
- if (OS_MEMORY_COMPARE(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH )) // Is equal
- {
- memcpy( pMacAddr, pMacAddr2, MAC_ADDR_LENGTH );
- } else {
- // Set the user define MAC address
- hal_set_ethernet_address( pHwData, Adapter->sLocalPara.ThisMacAddress );
- }
+ // Get Software setting flag from hal
+ Adapter->sLocalPara.boAntennaDiversity = FALSE;
+ if (hal_software_set(pHwData) & 0x00000001)
+ Adapter->sLocalPara.boAntennaDiversity = TRUE;
+
+ //
+ // For TS module
+ //
+ InitStep = 2;
+
+ // For MDS module
+ InitStep = 3;
+ Mds_initial(Adapter);
+
+ //=======================================
+ // Initialize the SME, SCAN, MLME, ROAM
+ //=======================================
+ InitStep = 4;
+ InitStep = 5;
+ InitStep = 6;
+
+ // If no user-defined address in the registry, use the addresss "burned" on the NIC instead.
+ pMacAddr = Adapter->sLocalPara.ThisMacAddress;
+ pMacAddr2 = Adapter->sLocalPara.PermanentAddress;
+ hal_get_permanent_address( pHwData, Adapter->sLocalPara.PermanentAddress );// Reading ethernet address from EEPROM
+ if (OS_MEMORY_COMPARE(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH )) // Is equal
+ {
+ memcpy( pMacAddr, pMacAddr2, MAC_ADDR_LENGTH );
+ } else {
+ // Set the user define MAC address
+ hal_set_ethernet_address( pHwData, Adapter->sLocalPara.ThisMacAddress );
+ }
- //get current antenna
- psLOCAL->bAntennaNo = hal_get_antenna_number(pHwData);
+ //get current antenna
+ psLOCAL->bAntennaNo = hal_get_antenna_number(pHwData);
#ifdef _PE_STATE_DUMP_
- WBDEBUG(("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo));
+ WBDEBUG(("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo));
#endif
- hal_get_hw_radio_off( pHwData );
+ hal_get_hw_radio_off( pHwData );
- // Waiting for HAL setting OK
- while (!hal_idle(pHwData))
- OS_SLEEP(10000);
+ // Waiting for HAL setting OK
+ while (!hal_idle(pHwData))
+ OS_SLEEP(10000);
- MTO_Init(Adapter);
+ MTO_Init(Adapter);
- HwRadioOff = hal_get_hw_radio_off( pHwData );
- psLOCAL->RadioOffStatus.boHwRadioOff = !!HwRadioOff;
+ HwRadioOff = hal_get_hw_radio_off( pHwData );
+ psLOCAL->RadioOffStatus.boHwRadioOff = !!HwRadioOff;
- hal_set_radio_mode( pHwData, (unsigned char)(psLOCAL->RadioOffStatus.boSwRadioOff || psLOCAL->RadioOffStatus.boHwRadioOff) );
+ hal_set_radio_mode( pHwData, (unsigned char)(psLOCAL->RadioOffStatus.boSwRadioOff || psLOCAL->RadioOffStatus.boHwRadioOff) );
- hal_driver_init_OK(pHwData) = 1; // Notify hal that the driver is ready now.
- //set a tx power for reference.....
-// sme_set_tx_power_level(Adapter, 12); FIXME?
- return TRUE;
- }
- while(FALSE);
+ hal_driver_init_OK(pHwData) = 1; // Notify hal that the driver is ready now.
+ //set a tx power for reference.....
+// sme_set_tx_power_level(Adapter, 12); FIXME?
+ return TRUE;
+error:
switch (InitStep) {
case 5:
case 4:
diff --git a/drivers/staging/winbond/wblinux_s.h b/drivers/staging/winbond/wblinux_s.h
index 97e9167ab83..fd2bb43bf3c 100644
--- a/drivers/staging/winbond/wblinux_s.h
+++ b/drivers/staging/winbond/wblinux_s.h
@@ -24,8 +24,8 @@
typedef struct _WBLINUX
{
- OS_SPIN_LOCK AtomicSpinLock;
- OS_SPIN_LOCK SpinLock;
+ spinlock_t AtomicSpinLock;
+ spinlock_t SpinLock;
u32 shutdown;
OS_ATOMIC ThreadCount;
diff --git a/drivers/staging/wlan-ng/Kconfig b/drivers/staging/wlan-ng/Kconfig
index 10b1f0f634d..2425d860dca 100644
--- a/drivers/staging/wlan-ng/Kconfig
+++ b/drivers/staging/wlan-ng/Kconfig
@@ -1,6 +1,6 @@
config PRISM2_USB
tristate "Prism2.5 USB driver"
- depends on USB
+ depends on WLAN_80211 && USB
default n
---help---
This is the wlan-ng prism 2.5 USB driver for a wide range of
diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h
index a2054639d24..0dfb8ce9aae 100644
--- a/drivers/staging/wlan-ng/hfa384x.h
+++ b/drivers/staging/wlan-ng/hfa384x.h
@@ -824,7 +824,7 @@ PD Record codes
#define HFA384x_CMD_MACPORT_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET(value))
#define HFA384x_CMD_ISRECL(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_RECL)))
#define HFA384x_CMD_RECL_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET(value))
-#define HFA384x_CMD_QOS_GET(value) ((UINT16((((UINT16)(value))&((UINT16)0x3000)) >> 12))
+#define HFA384x_CMD_QOS_GET(value) ((UINT16)((((UINT16)(value))&((UINT16)0x3000)) >> 12))
#define HFA384x_CMD_QOS_SET(value) ((UINT16)((((UINT16)(value)) << 12) & 0x3000))
#define HFA384x_CMD_ISWRITE(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_WRITE)))
#define HFA384x_CMD_WRITE_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET((UINT16)value))
diff --git a/drivers/staging/wlan-ng/p80211wep.c b/drivers/staging/wlan-ng/p80211wep.c
index 53fe2985971..11a50c7fbfc 100644
--- a/drivers/staging/wlan-ng/p80211wep.c
+++ b/drivers/staging/wlan-ng/p80211wep.c
@@ -64,7 +64,6 @@
/*================================================================*/
/* Project Includes */
-#include "version.h"
#include "p80211hdr.h"
#include "p80211types.h"
#include "p80211msg.h"
diff --git a/drivers/staging/wlan-ng/prism2mib.c b/drivers/staging/wlan-ng/prism2mib.c
index 268fd9bba1e..eac06f793d8 100644
--- a/drivers/staging/wlan-ng/prism2mib.c
+++ b/drivers/staging/wlan-ng/prism2mib.c
@@ -90,8 +90,6 @@
#include <linux/usb.h>
//#endif
-#include "wlan_compat.h"
-
/*================================================================*/
/* Project Includes */
diff --git a/drivers/staging/wlan-ng/wlan_compat.h b/drivers/staging/wlan-ng/wlan_compat.h
index 17026570708..59dfa8f84cb 100644
--- a/drivers/staging/wlan-ng/wlan_compat.h
+++ b/drivers/staging/wlan-ng/wlan_compat.h
@@ -245,11 +245,11 @@ typedef int64_t INT64;
# define preempt_count() (0UL)
#endif
-#define WLAN_LOG_ERROR(x,args...) printk(KERN_ERR "%s: " x , __FUNCTION__ , ##args);
+#define WLAN_LOG_ERROR(x,args...) printk(KERN_ERR "%s: " x , __func__ , ##args);
-#define WLAN_LOG_WARNING(x,args...) printk(KERN_WARNING "%s: " x , __FUNCTION__ , ##args);
+#define WLAN_LOG_WARNING(x,args...) printk(KERN_WARNING "%s: " x , __func__ , ##args);
-#define WLAN_LOG_NOTICE(x,args...) printk(KERN_NOTICE "%s: " x , __FUNCTION__ , ##args);
+#define WLAN_LOG_NOTICE(x,args...) printk(KERN_NOTICE "%s: " x , __func__ , ##args);
#define WLAN_LOG_INFO(args... ) printk(KERN_INFO args)
@@ -265,7 +265,7 @@ typedef int64_t INT64;
#define DBFENTER { if ( WLAN_DBVAR >= 5 ){ WLAN_LOG_DEBUG(3,"---->\n"); } }
#define DBFEXIT { if ( WLAN_DBVAR >= 5 ){ WLAN_LOG_DEBUG(3,"<----\n"); } }
- #define WLAN_LOG_DEBUG(l,x,args...) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s(%lu): " x , __FUNCTION__, (preempt_count() & PREEMPT_MASK), ##args );
+ #define WLAN_LOG_DEBUG(l,x,args...) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s(%lu): " x , __func__, (preempt_count() & PREEMPT_MASK), ##args );
#else
#define WLAN_ASSERT(c)
#define WLAN_HEX_DUMP( l, s, p, n)
diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c
index 4d74ba36c3a..37caf4d6903 100644
--- a/drivers/telephony/phonedev.c
+++ b/drivers/telephony/phonedev.c
@@ -54,7 +54,6 @@ static int phone_open(struct inode *inode, struct file *file)
if (minor >= PHONE_NUM_DEVICES)
return -ENODEV;
- lock_kernel();
mutex_lock(&phone_lock);
p = phone_device[minor];
if (p)
@@ -81,7 +80,6 @@ static int phone_open(struct inode *inode, struct file *file)
fops_put(old_fops);
end:
mutex_unlock(&phone_lock);
- unlock_kernel();
return err;
}
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 5dccf057a7d..f9b4647255a 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -47,6 +47,9 @@ static struct uio_class {
struct class *class;
} *uio_class;
+/* Protect idr accesses */
+static DEFINE_MUTEX(minor_lock);
+
/*
* attributes
*/
@@ -239,7 +242,6 @@ static void uio_dev_del_attributes(struct uio_device *idev)
static int uio_get_minor(struct uio_device *idev)
{
- static DEFINE_MUTEX(minor_lock);
int retval = -ENOMEM;
int id;
@@ -261,7 +263,9 @@ exit:
static void uio_free_minor(struct uio_device *idev)
{
+ mutex_lock(&minor_lock);
idr_remove(&uio_idr, idev->minor);
+ mutex_unlock(&minor_lock);
}
/**
@@ -305,8 +309,9 @@ static int uio_open(struct inode *inode, struct file *filep)
struct uio_listener *listener;
int ret = 0;
- lock_kernel();
+ mutex_lock(&minor_lock);
idev = idr_find(&uio_idr, iminor(inode));
+ mutex_unlock(&minor_lock);
if (!idev) {
ret = -ENODEV;
goto out;
@@ -332,18 +337,15 @@ static int uio_open(struct inode *inode, struct file *filep)
if (ret)
goto err_infoopen;
}
- unlock_kernel();
return 0;
err_infoopen:
-
kfree(listener);
-err_alloc_listener:
+err_alloc_listener:
module_put(idev->owner);
out:
- unlock_kernel();
return ret;
}
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index bcefbddeba5..289d81adfb9 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -36,7 +36,8 @@ config USB_ARCH_HAS_OHCI
default y if PXA3xx
default y if ARCH_EP93XX
default y if ARCH_AT91
- default y if ARCH_PNX4008
+ default y if ARCH_PNX4008 && I2C
+ default y if MFD_TC6393XB
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx
@@ -97,6 +98,8 @@ source "drivers/usb/core/Kconfig"
source "drivers/usb/mon/Kconfig"
+source "drivers/usb/wusbcore/Kconfig"
+
source "drivers/usb/host/Kconfig"
source "drivers/usb/musb/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index a419c42e880..8b7c419b876 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -16,9 +16,12 @@ obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
+obj-$(CONFIG_USB_HWA_HCD) += host/
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
+obj-$(CONFIG_USB_WUSB) += wusbcore/
+
obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_PRINTER) += class/
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 76fce44c2f9..3e862401a63 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -722,6 +722,16 @@ static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_de
flush_scheduled_work();
}
+static int speedtch_pre_reset(struct usb_interface *intf)
+{
+ return 0;
+}
+
+static int speedtch_post_reset(struct usb_interface *intf)
+{
+ return 0;
+}
+
/**********
** USB **
@@ -740,6 +750,8 @@ static struct usb_driver speedtch_usb_driver = {
.name = speedtch_driver_name,
.probe = speedtch_usb_probe,
.disconnect = usbatm_usb_disconnect,
+ .pre_reset = speedtch_pre_reset,
+ .post_reset = speedtch_post_reset,
.id_table = speedtch_usb_ids
};
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 0da2c25bab3..06dd114910d 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -344,7 +344,7 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char
__func__, sarb->len, vcc);
/* discard cells already received */
skb_trim(sarb, 0);
- UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
+ UDSL_ASSERT(instance, sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
}
memcpy(skb_tail_pointer(sarb), source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
@@ -432,7 +432,7 @@ static void usbatm_extract_cells(struct usbatm_data *instance,
unsigned char *cell_buf = instance->cell_buf;
unsigned int space_left = stride - buf_usage;
- UDSL_ASSERT(buf_usage <= stride);
+ UDSL_ASSERT(instance, buf_usage <= stride);
if (avail_data >= space_left) {
/* add new data and process cell */
@@ -475,7 +475,7 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance,
unsigned int stride = instance->tx_channel.stride;
vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space);
- UDSL_ASSERT(!(avail_space % stride));
+ UDSL_ASSERT(instance, !(avail_space % stride));
for (bytes_written = 0; bytes_written < avail_space && ctrl->len;
bytes_written += stride, target += stride) {
@@ -547,7 +547,7 @@ static void usbatm_rx_process(unsigned long data)
if (!urb->iso_frame_desc[i].status) {
unsigned int actual_length = urb->iso_frame_desc[i].actual_length;
- UDSL_ASSERT(actual_length <= packet_size);
+ UDSL_ASSERT(instance, actual_length <= packet_size);
if (!merge_length)
merge_start = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
@@ -1188,7 +1188,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
struct urb *urb;
unsigned int iso_packets = usb_pipeisoc(channel->endpoint) ? channel->buf_size / channel->packet_size : 0;
- UDSL_ASSERT(!usb_pipeisoc(channel->endpoint) || usb_pipein(channel->endpoint));
+ UDSL_ASSERT(instance, !usb_pipeisoc(channel->endpoint) || usb_pipein(channel->endpoint));
urb = usb_alloc_urb(iso_packets, GFP_KERNEL);
if (!urb) {
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
index e6887c6cf3c..f6f4508a9d4 100644
--- a/drivers/usb/atm/usbatm.h
+++ b/drivers/usb/atm/usbatm.h
@@ -40,9 +40,15 @@
*/
#ifdef DEBUG
-#define UDSL_ASSERT(x) BUG_ON(!(x))
+#define UDSL_ASSERT(instance, x) BUG_ON(!(x))
#else
-#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '%s' at line %d", __stringify(x), __LINE__); } while(0)
+#define UDSL_ASSERT(instance, x) \
+ do { \
+ if (!(x)) \
+ dev_warn(&(instance)->usb_intf->dev, \
+ "failed assertion '%s' at line %d", \
+ __stringify(x), __LINE__); \
+ } while(0)
#endif
#define usb_err(instance, format, arg...) \
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
index 8472543eee8..17d167bbd2d 100644
--- a/drivers/usb/atm/xusbatm.c
+++ b/drivers/usb/atm/xusbatm.c
@@ -193,7 +193,7 @@ static int __init xusbatm_init(void)
num_vendor != num_product ||
num_vendor != num_rx_endpoint ||
num_vendor != num_tx_endpoint) {
- warn("malformed module parameters");
+ printk(KERN_WARNING "xusbatm: malformed module parameters\n");
return -EINVAL;
}
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 66f17ed88cb..2519e320098 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -40,3 +40,13 @@ config USB_WDM
To compile this driver as a module, choose M here: the
module will be called cdc-wdm.
+config USB_TMC
+ tristate "USB Test and Measurement Class support"
+ depends on USB
+ help
+ Say Y here if you want to connect a USB device that follows
+ the USB.org specification for USB Test and Measurement devices
+ to your computer's USB port.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbtmc.
diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
index 535d59a3060..32e85277b5c 100644
--- a/drivers/usb/class/Makefile
+++ b/drivers/usb/class/Makefile
@@ -6,3 +6,4 @@
obj-$(CONFIG_USB_ACM) += cdc-acm.o
obj-$(CONFIG_USB_PRINTER) += usblp.o
obj-$(CONFIG_USB_WDM) += cdc-wdm.o
+obj-$(CONFIG_USB_TMC) += usbtmc.o
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index c257453fa9d..20104443081 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -326,8 +326,8 @@ exit:
usb_mark_last_busy(acm->dev);
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
+ "result %d", __func__, retval);
}
/* data interface returns incoming bytes, or we got unthrottled */
@@ -514,7 +514,7 @@ static void acm_waker(struct work_struct *waker)
rv = usb_autopm_get_interface(acm->control);
if (rv < 0) {
- err("Autopm failure in %s", __func__);
+ dev_err(&acm->dev->dev, "Autopm failure in %s\n", __func__);
return;
}
if (acm->delayed_wb) {
@@ -849,9 +849,10 @@ static void acm_write_buffers_free(struct acm *acm)
{
int i;
struct acm_wb *wb;
+ struct usb_device *usb_dev = interface_to_usbdev(acm->control);
for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
- usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
+ usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah);
}
}
@@ -924,7 +925,7 @@ static int acm_probe (struct usb_interface *intf,
/* normal probing*/
if (!buffer) {
- err("Weird descriptor references\n");
+ dev_err(&intf->dev, "Weird descriptor references\n");
return -EINVAL;
}
@@ -934,21 +935,24 @@ static int acm_probe (struct usb_interface *intf,
buflen = intf->cur_altsetting->endpoint->extralen;
buffer = intf->cur_altsetting->endpoint->extra;
} else {
- err("Zero length descriptor references\n");
+ dev_err(&intf->dev,
+ "Zero length descriptor references\n");
return -EINVAL;
}
}
while (buflen > 0) {
if (buffer [1] != USB_DT_CS_INTERFACE) {
- err("skipping garbage\n");
+ dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer [2]) {
case USB_CDC_UNION_TYPE: /* we've found it */
if (union_header) {
- err("More than one union descriptor, skipping ...");
+ dev_err(&intf->dev, "More than one "
+ "union descriptor, "
+ "skipping ...\n");
goto next_desc;
}
union_header = (struct usb_cdc_union_desc *)
@@ -966,7 +970,9 @@ static int acm_probe (struct usb_interface *intf,
call_management_function = buffer[3];
call_interface_num = buffer[4];
if ((call_management_function & 3) != 3)
- err("This device cannot do calls on its own. It is no modem.");
+ dev_err(&intf->dev, "This device "
+ "cannot do calls on its own. "
+ "It is no modem.\n");
break;
default:
/* there are LOTS more CDC descriptors that
@@ -1051,7 +1057,7 @@ skip_normal_probe:
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
if (minor == ACM_TTY_MINORS) {
- err("no more free acm devices");
+ dev_err(&intf->dev, "no more free acm devices\n");
return -ENODEV;
}
@@ -1454,7 +1460,8 @@ static int __init acm_init(void)
return retval;
}
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
}
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 7e8e1235e4e..5a8ecc045e3 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -42,6 +42,8 @@ static struct usb_device_id wdm_ids[] = {
{ }
};
+MODULE_DEVICE_TABLE (usb, wdm_ids);
+
#define WDM_MINOR_BASE 176
@@ -132,10 +134,12 @@ static void wdm_in_callback(struct urb *urb)
"nonzero urb status received: -ESHUTDOWN");
break;
case -EPIPE:
- err("nonzero urb status received: -EPIPE");
+ dev_err(&desc->intf->dev,
+ "nonzero urb status received: -EPIPE\n");
break;
default:
- err("Unexpected error %d", status);
+ dev_err(&desc->intf->dev,
+ "Unexpected error %d\n", status);
break;
}
}
@@ -170,16 +174,18 @@ static void wdm_int_callback(struct urb *urb)
return; /* unplug */
case -EPIPE:
set_bit(WDM_INT_STALL, &desc->flags);
- err("Stall on int endpoint");
+ dev_err(&desc->intf->dev, "Stall on int endpoint\n");
goto sw; /* halt is cleared in work */
default:
- err("nonzero urb status received: %d", status);
+ dev_err(&desc->intf->dev,
+ "nonzero urb status received: %d\n", status);
break;
}
}
if (urb->actual_length < sizeof(struct usb_cdc_notification)) {
- err("wdm_int_callback - %d bytes", urb->actual_length);
+ dev_err(&desc->intf->dev, "wdm_int_callback - %d bytes\n",
+ urb->actual_length);
goto exit;
}
@@ -198,7 +204,8 @@ static void wdm_int_callback(struct urb *urb)
goto exit;
default:
clear_bit(WDM_POLL_RUNNING, &desc->flags);
- err("unknown notification %d received: index %d len %d",
+ dev_err(&desc->intf->dev,
+ "unknown notification %d received: index %d len %d\n",
dr->bNotificationType, dr->wIndex, dr->wLength);
goto exit;
}
@@ -236,14 +243,16 @@ static void wdm_int_callback(struct urb *urb)
sw:
rv = schedule_work(&desc->rxwork);
if (rv)
- err("Cannot schedule work");
+ dev_err(&desc->intf->dev,
+ "Cannot schedule work\n");
}
}
exit:
rv = usb_submit_urb(urb, GFP_ATOMIC);
if (rv)
- err("%s - usb_submit_urb failed with result %d",
- __func__, rv);
+ dev_err(&desc->intf->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, rv);
}
@@ -353,7 +362,7 @@ static ssize_t wdm_write
if (rv < 0) {
kfree(buf);
clear_bit(WDM_IN_USE, &desc->flags);
- err("Tx URB error: %d", rv);
+ dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv);
} else {
dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d",
req->wIndex);
@@ -401,7 +410,8 @@ retry:
int t = desc->rerr;
desc->rerr = 0;
spin_unlock_irq(&desc->iuspin);
- err("reading had resulted in %d", t);
+ dev_err(&desc->intf->dev,
+ "reading had resulted in %d\n", t);
rv = -EIO;
goto err;
}
@@ -440,7 +450,7 @@ retry:
err:
mutex_unlock(&desc->rlock);
if (rv < 0)
- err("wdm_read: exit error");
+ dev_err(&desc->intf->dev, "wdm_read: exit error\n");
return rv;
}
@@ -450,7 +460,8 @@ static int wdm_flush(struct file *file, fl_owner_t id)
wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags));
if (desc->werr < 0)
- err("Error in flush path: %d", desc->werr);
+ dev_err(&desc->intf->dev, "Error in flush path: %d\n",
+ desc->werr);
return desc->werr;
}
@@ -502,7 +513,7 @@ static int wdm_open(struct inode *inode, struct file *file)
rv = usb_autopm_get_interface(desc->intf);
if (rv < 0) {
- err("Error autopm - %d", rv);
+ dev_err(&desc->intf->dev, "Error autopm - %d\n", rv);
goto out;
}
intf->needs_remote_wakeup = 1;
@@ -512,7 +523,8 @@ static int wdm_open(struct inode *inode, struct file *file)
rv = usb_submit_urb(desc->validity, GFP_KERNEL);
if (rv < 0) {
desc->count--;
- err("Error submitting int urb - %d", rv);
+ dev_err(&desc->intf->dev,
+ "Error submitting int urb - %d\n", rv);
}
} else {
rv = 0;
@@ -600,7 +612,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
while (buflen > 0) {
if (buffer [1] != USB_DT_CS_INTERFACE) {
- err("skipping garbage");
+ dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
@@ -614,7 +626,8 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
"Finding maximum buffer length: %d", maxcom);
break;
default:
- err("Ignoring extra header, type %d, length %d",
+ dev_err(&intf->dev,
+ "Ignoring extra header, type %d, length %d\n",
buffer[2], buffer[0]);
break;
}
@@ -772,7 +785,8 @@ static int recover_from_urb_loss(struct wdm_device *desc)
if (desc->count) {
rv = usb_submit_urb(desc->validity, GFP_NOIO);
if (rv < 0)
- err("Error resume submitting int urb - %d", rv);
+ dev_err(&desc->intf->dev,
+ "Error resume submitting int urb - %d\n", rv);
}
return rv;
}
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 0647164d36d..b5775af3ba2 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -593,8 +593,9 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = usblp_hp_channel_change_request(usblp,
arg, &newChannel);
if (err < 0) {
- err("usblp%d: error = %d setting "
- "HP channel",
+ dev_err(&usblp->dev->dev,
+ "usblp%d: error = %d setting "
+ "HP channel\n",
usblp->minor, err);
retval = -EIO;
goto done;
@@ -1076,15 +1077,16 @@ static int usblp_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev (intf);
- struct usblp *usblp = NULL;
+ struct usblp *usblp;
int protocol;
int retval;
/* Malloc and start initializing usblp structure so we can use it
* directly. */
- if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) {
+ usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL);
+ if (!usblp) {
retval = -ENOMEM;
- goto abort;
+ goto abort_ret;
}
usblp->dev = dev;
mutex_init(&usblp->wmut);
@@ -1179,12 +1181,11 @@ abort_intfdata:
usb_set_intfdata (intf, NULL);
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
abort:
- if (usblp) {
- kfree(usblp->readbuf);
- kfree(usblp->statusbuf);
- kfree(usblp->device_id_string);
- kfree(usblp);
- }
+ kfree(usblp->readbuf);
+ kfree(usblp->statusbuf);
+ kfree(usblp->device_id_string);
+ kfree(usblp);
+abort_ret:
return retval;
}
@@ -1345,7 +1346,7 @@ static void usblp_disconnect(struct usb_interface *intf)
usb_deregister_dev(intf, &usblp_class);
if (!usblp || !usblp->dev) {
- err("bogus disconnect");
+ dev_err(&intf->dev, "bogus disconnect\n");
BUG ();
}
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
new file mode 100644
index 00000000000..543811f6e6e
--- /dev/null
+++ b/drivers/usb/class/usbtmc.c
@@ -0,0 +1,1087 @@
+/**
+ * drivers/usb/class/usbtmc.c - USB Test & Measurment class driver
+ *
+ * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
+ * Copyright (C) 2008 Novell, Inc.
+ * Copyright (C) 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
+ * 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.
+ *
+ * The GNU General Public License is available at
+ * http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/usb/tmc.h>
+
+
+#define USBTMC_MINOR_BASE 176
+
+/*
+ * Size of driver internal IO buffer. Must be multiple of 4 and at least as
+ * large as wMaxPacketSize (which is usually 512 bytes).
+ */
+#define USBTMC_SIZE_IOBUFFER 2048
+
+/* Default USB timeout (in milliseconds) */
+#define USBTMC_TIMEOUT 10
+
+/*
+ * Maximum number of read cycles to empty bulk in endpoint during CLEAR and
+ * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short
+ * packet is never read.
+ */
+#define USBTMC_MAX_READS_TO_CLEAR_BULK_IN 100
+
+static struct usb_device_id usbtmc_devices[] = {
+ { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), },
+ { 0, } /* terminating entry */
+};
+
+/*
+ * This structure is the capabilities for the device
+ * See section 4.2.1.8 of the USBTMC specification for details.
+ */
+struct usbtmc_dev_capabilities {
+ __u8 interface_capabilities;
+ __u8 device_capabilities;
+ __u8 usb488_interface_capabilities;
+ __u8 usb488_device_capabilities;
+};
+
+/* This structure holds private data for each USBTMC device. One copy is
+ * allocated for each USBTMC device in the driver's probe function.
+ */
+struct usbtmc_device_data {
+ const struct usb_device_id *id;
+ struct usb_device *usb_dev;
+ struct usb_interface *intf;
+
+ unsigned int bulk_in;
+ unsigned int bulk_out;
+
+ u8 bTag;
+ u8 bTag_last_write; /* needed for abort */
+ u8 bTag_last_read; /* needed for abort */
+
+ /* attributes from the USB TMC spec for this device */
+ u8 TermChar;
+ bool TermCharEnabled;
+ bool auto_abort;
+
+ struct usbtmc_dev_capabilities capabilities;
+ struct kref kref;
+ struct mutex io_mutex; /* only one i/o function running at a time */
+};
+#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
+
+/* Forward declarations */
+static struct usb_driver usbtmc_driver;
+
+static void usbtmc_delete(struct kref *kref)
+{
+ struct usbtmc_device_data *data = to_usbtmc_data(kref);
+
+ usb_put_dev(data->usb_dev);
+ kfree(data);
+}
+
+static int usbtmc_open(struct inode *inode, struct file *filp)
+{
+ struct usb_interface *intf;
+ struct usbtmc_device_data *data;
+ int retval = -ENODEV;
+
+ intf = usb_find_interface(&usbtmc_driver, iminor(inode));
+ if (!intf) {
+ printk(KERN_ERR KBUILD_MODNAME
+ ": can not find device for minor %d", iminor(inode));
+ goto exit;
+ }
+
+ data = usb_get_intfdata(intf);
+ kref_get(&data->kref);
+
+ /* Store pointer in file structure's private data field */
+ filp->private_data = data;
+
+exit:
+ return retval;
+}
+
+static int usbtmc_release(struct inode *inode, struct file *file)
+{
+ struct usbtmc_device_data *data = file->private_data;
+
+ kref_put(&data->kref, usbtmc_delete);
+ return 0;
+}
+
+static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
+{
+ char *buffer;
+ struct device *dev;
+ int rv;
+ int n;
+ int actual;
+ struct usb_host_interface *current_setting;
+ int max_size;
+
+ dev = &data->intf->dev;
+ buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC_REQUEST_INITIATE_ABORT_BULK_IN,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
+ data->bTag_last_read, data->bulk_in,
+ buffer, 2, USBTMC_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+
+ dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+
+ if (buffer[0] == USBTMC_STATUS_FAILED) {
+ rv = 0;
+ goto exit;
+ }
+
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
+ buffer[0]);
+ rv = -EPERM;
+ goto exit;
+ }
+
+ max_size = 0;
+ current_setting = data->intf->cur_altsetting;
+ for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
+ if (current_setting->endpoint[n].desc.bEndpointAddress ==
+ data->bulk_in)
+ max_size = le16_to_cpu(current_setting->endpoint[n].
+ desc.wMaxPacketSize);
+
+ if (max_size == 0) {
+ dev_err(dev, "Couldn't get wMaxPacketSize\n");
+ rv = -EPERM;
+ goto exit;
+ }
+
+ dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size);
+
+ n = 0;
+
+ do {
+ dev_dbg(dev, "Reading from bulk in EP\n");
+
+ rv = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, USBTMC_SIZE_IOBUFFER,
+ &actual, USBTMC_TIMEOUT);
+
+ n++;
+
+ if (rv < 0) {
+ dev_err(dev, "usb_bulk_msg returned %d\n", rv);
+ goto exit;
+ }
+ } while ((actual == max_size) &&
+ (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
+
+ if (actual == max_size) {
+ dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
+ USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
+ rv = -EPERM;
+ goto exit;
+ }
+
+ n = 0;
+
+usbtmc_abort_bulk_in_status:
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
+ 0, data->bulk_in, buffer, 0x08,
+ USBTMC_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+
+ dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+
+ if (buffer[0] == USBTMC_STATUS_SUCCESS) {
+ rv = 0;
+ goto exit;
+ }
+
+ if (buffer[0] != USBTMC_STATUS_PENDING) {
+ dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+ rv = -EPERM;
+ goto exit;
+ }
+
+ if (buffer[1] == 1)
+ do {
+ dev_dbg(dev, "Reading from bulk in EP\n");
+
+ rv = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, USBTMC_SIZE_IOBUFFER,
+ &actual, USBTMC_TIMEOUT);
+
+ n++;
+
+ if (rv < 0) {
+ dev_err(dev, "usb_bulk_msg returned %d\n", rv);
+ goto exit;
+ }
+ } while ((actual = max_size) &&
+ (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
+
+ if (actual == max_size) {
+ dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
+ USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
+ rv = -EPERM;
+ goto exit;
+ }
+
+ goto usbtmc_abort_bulk_in_status;
+
+exit:
+ kfree(buffer);
+ return rv;
+
+}
+
+static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+{
+ struct device *dev;
+ u8 *buffer;
+ int rv;
+ int n;
+
+ dev = &data->intf->dev;
+
+ buffer = kmalloc(8, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
+ data->bTag_last_write, data->bulk_out,
+ buffer, 2, USBTMC_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+
+ dev_dbg(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", buffer[0]);
+
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "INITIATE_ABORT_BULK_OUT returned %x\n",
+ buffer[0]);
+ rv = -EPERM;
+ goto exit;
+ }
+
+ n = 0;
+
+usbtmc_abort_bulk_out_check_status:
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
+ 0, data->bulk_out, buffer, 0x08,
+ USBTMC_TIMEOUT);
+ n++;
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+
+ dev_dbg(dev, "CHECK_ABORT_BULK_OUT returned %x\n", buffer[0]);
+
+ if (buffer[0] == USBTMC_STATUS_SUCCESS)
+ goto usbtmc_abort_bulk_out_clear_halt;
+
+ if ((buffer[0] == USBTMC_STATUS_PENDING) &&
+ (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN))
+ goto usbtmc_abort_bulk_out_check_status;
+
+ rv = -EPERM;
+ goto exit;
+
+usbtmc_abort_bulk_out_clear_halt:
+ rv = usb_control_msg(data->usb_dev,
+ usb_sndctrlpipe(data->usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_ENDPOINT,
+ USB_ENDPOINT_HALT, data->bulk_out, buffer,
+ 0, USBTMC_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+ rv = 0;
+
+exit:
+ kfree(buffer);
+ return rv;
+}
+
+static ssize_t usbtmc_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct usbtmc_device_data *data;
+ struct device *dev;
+ unsigned long int n_characters;
+ u8 *buffer;
+ int actual;
+ int done;
+ int remaining;
+ int retval;
+ int this_part;
+
+ /* Get pointer to private data structure */
+ data = filp->private_data;
+ dev = &data->intf->dev;
+
+ buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ mutex_lock(&data->io_mutex);
+
+ remaining = count;
+ done = 0;
+
+ while (remaining > 0) {
+ if (remaining > USBTMC_SIZE_IOBUFFER - 12 - 3)
+ this_part = USBTMC_SIZE_IOBUFFER - 12 - 3;
+ else
+ this_part = remaining;
+
+ /* Setup IO buffer for DEV_DEP_MSG_IN message
+ * Refer to class specs for details
+ */
+ buffer[0] = 2;
+ buffer[1] = data->bTag;
+ buffer[2] = ~(data->bTag);
+ buffer[3] = 0; /* Reserved */
+ buffer[4] = (this_part - 12 - 3) & 255;
+ buffer[5] = ((this_part - 12 - 3) >> 8) & 255;
+ buffer[6] = ((this_part - 12 - 3) >> 16) & 255;
+ buffer[7] = ((this_part - 12 - 3) >> 24) & 255;
+ buffer[8] = data->TermCharEnabled * 2;
+ /* Use term character? */
+ buffer[9] = data->TermChar;
+ buffer[10] = 0; /* Reserved */
+ buffer[11] = 0; /* Reserved */
+
+ /* Send bulk URB */
+ retval = usb_bulk_msg(data->usb_dev,
+ usb_sndbulkpipe(data->usb_dev,
+ data->bulk_out),
+ buffer, 12, &actual, USBTMC_TIMEOUT);
+
+ /* Store bTag (in case we need to abort) */
+ data->bTag_last_write = data->bTag;
+
+ /* Increment bTag -- and increment again if zero */
+ data->bTag++;
+ if (!data->bTag)
+ (data->bTag)++;
+
+ if (retval < 0) {
+ dev_err(dev, "usb_bulk_msg returned %d\n", retval);
+ if (data->auto_abort)
+ usbtmc_ioctl_abort_bulk_out(data);
+ goto exit;
+ }
+
+ /* Send bulk URB */
+ retval = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, USBTMC_SIZE_IOBUFFER, &actual,
+ USBTMC_TIMEOUT);
+
+ /* Store bTag (in case we need to abort) */
+ data->bTag_last_read = data->bTag;
+
+ if (retval < 0) {
+ dev_err(dev, "Unable to read data, error %d\n", retval);
+ if (data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
+
+ /* How many characters did the instrument send? */
+ n_characters = buffer[4] +
+ (buffer[5] << 8) +
+ (buffer[6] << 16) +
+ (buffer[7] << 24);
+
+ /* Copy buffer to user space */
+ if (copy_to_user(buf + done, &buffer[12], n_characters)) {
+ /* There must have been an addressing problem */
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ done += n_characters;
+ if (n_characters < USBTMC_SIZE_IOBUFFER)
+ remaining = 0;
+ }
+
+ /* Update file position value */
+ *f_pos = *f_pos + done;
+ retval = done;
+
+exit:
+ mutex_unlock(&data->io_mutex);
+ kfree(buffer);
+ return retval;
+}
+
+static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct usbtmc_device_data *data;
+ u8 *buffer;
+ int retval;
+ int actual;
+ unsigned long int n_bytes;
+ int n;
+ int remaining;
+ int done;
+ int this_part;
+
+ data = filp->private_data;
+
+ buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ mutex_lock(&data->io_mutex);
+
+ remaining = count;
+ done = 0;
+
+ while (remaining > 0) {
+ if (remaining > USBTMC_SIZE_IOBUFFER - 12) {
+ this_part = USBTMC_SIZE_IOBUFFER - 12;
+ buffer[8] = 0;
+ } else {
+ this_part = remaining;
+ buffer[8] = 1;
+ }
+
+ /* Setup IO buffer for DEV_DEP_MSG_OUT message */
+ buffer[0] = 1;
+ buffer[1] = data->bTag;
+ buffer[2] = ~(data->bTag);
+ buffer[3] = 0; /* Reserved */
+ buffer[4] = this_part & 255;
+ buffer[5] = (this_part >> 8) & 255;
+ buffer[6] = (this_part >> 16) & 255;
+ buffer[7] = (this_part >> 24) & 255;
+ /* buffer[8] is set above... */
+ buffer[9] = 0; /* Reserved */
+ buffer[10] = 0; /* Reserved */
+ buffer[11] = 0; /* Reserved */
+
+ if (copy_from_user(&buffer[12], buf + done, this_part)) {
+ retval = -EFAULT;
+ 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;
+
+ retval = usb_bulk_msg(data->usb_dev,
+ usb_sndbulkpipe(data->usb_dev,
+ data->bulk_out),
+ buffer, n_bytes, &actual, USBTMC_TIMEOUT);
+
+ data->bTag_last_write = data->bTag;
+ data->bTag++;
+
+ if (!data->bTag)
+ data->bTag++;
+
+ if (retval < 0) {
+ dev_err(&data->intf->dev,
+ "Unable to send data, error %d\n", retval);
+ if (data->auto_abort)
+ usbtmc_ioctl_abort_bulk_out(data);
+ goto exit;
+ }
+
+ remaining -= this_part;
+ done += this_part;
+ }
+
+ retval = count;
+exit:
+ mutex_unlock(&data->io_mutex);
+ kfree(buffer);
+ return retval;
+}
+
+static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
+{
+ struct usb_host_interface *current_setting;
+ struct usb_endpoint_descriptor *desc;
+ struct device *dev;
+ u8 *buffer;
+ int rv;
+ int n;
+ int actual;
+ int max_size;
+
+ dev = &data->intf->dev;
+
+ dev_dbg(dev, "Sending INITIATE_CLEAR request\n");
+
+ buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC_REQUEST_INITIATE_CLEAR,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, 0, buffer, 1, USBTMC_TIMEOUT);
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+
+ dev_dbg(dev, "INITIATE_CLEAR returned %x\n", buffer[0]);
+
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "INITIATE_CLEAR returned %x\n", buffer[0]);
+ rv = -EPERM;
+ goto exit;
+ }
+
+ max_size = 0;
+ current_setting = data->intf->cur_altsetting;
+ for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
+ desc = &current_setting->endpoint[n].desc;
+ if (desc->bEndpointAddress == data->bulk_in)
+ max_size = le16_to_cpu(desc->wMaxPacketSize);
+ }
+
+ if (max_size == 0) {
+ dev_err(dev, "Couldn't get wMaxPacketSize\n");
+ rv = -EPERM;
+ goto exit;
+ }
+
+ dev_dbg(dev, "wMaxPacketSize is %d\n", max_size);
+
+ n = 0;
+
+usbtmc_clear_check_status:
+
+ dev_dbg(dev, "Sending CHECK_CLEAR_STATUS request\n");
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC_REQUEST_CHECK_CLEAR_STATUS,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, 0, buffer, 2, USBTMC_TIMEOUT);
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+
+ dev_dbg(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]);
+
+ if (buffer[0] == USBTMC_STATUS_SUCCESS)
+ goto usbtmc_clear_bulk_out_halt;
+
+ if (buffer[0] != USBTMC_STATUS_PENDING) {
+ dev_err(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]);
+ rv = -EPERM;
+ goto exit;
+ }
+
+ if (buffer[1] == 1)
+ do {
+ dev_dbg(dev, "Reading from bulk in EP\n");
+
+ rv = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, USBTMC_SIZE_IOBUFFER,
+ &actual, USBTMC_TIMEOUT);
+ n++;
+
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n",
+ rv);
+ goto exit;
+ }
+ } while ((actual == max_size) &&
+ (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
+
+ if (actual == max_size) {
+ dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
+ USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
+ rv = -EPERM;
+ goto exit;
+ }
+
+ goto usbtmc_clear_check_status;
+
+usbtmc_clear_bulk_out_halt:
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_sndctrlpipe(data->usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_ENDPOINT,
+ USB_ENDPOINT_HALT,
+ data->bulk_out, buffer, 0,
+ USBTMC_TIMEOUT);
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+ rv = 0;
+
+exit:
+ kfree(buffer);
+ return rv;
+}
+
+static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
+{
+ u8 *buffer;
+ int rv;
+
+ buffer = kmalloc(2, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_sndctrlpipe(data->usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_ENDPOINT,
+ USB_ENDPOINT_HALT, data->bulk_out,
+ buffer, 0, USBTMC_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
+ rv);
+ goto exit;
+ }
+ rv = 0;
+
+exit:
+ kfree(buffer);
+ return rv;
+}
+
+static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
+{
+ u8 *buffer;
+ int rv;
+
+ buffer = kmalloc(2, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ rv = usb_control_msg(data->usb_dev, usb_sndctrlpipe(data->usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_ENDPOINT,
+ USB_ENDPOINT_HALT, data->bulk_in, buffer, 0,
+ USBTMC_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
+ rv);
+ goto exit;
+ }
+ rv = 0;
+
+exit:
+ kfree(buffer);
+ return rv;
+}
+
+static int get_capabilities(struct usbtmc_device_data *data)
+{
+ struct device *dev = &data->usb_dev->dev;
+ char *buffer;
+ int rv;
+
+ buffer = kmalloc(0x18, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC_REQUEST_GET_CAPABILITIES,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, 0, buffer, 0x18, USBTMC_TIMEOUT);
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ return rv;
+ }
+
+ dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
+ dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]);
+ dev_dbg(dev, "Device capabilities are %x\n", buffer[5]);
+ dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]);
+ dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
+ return -EPERM;
+ }
+
+ data->capabilities.interface_capabilities = buffer[4];
+ data->capabilities.device_capabilities = buffer[5];
+ data->capabilities.usb488_interface_capabilities = buffer[14];
+ data->capabilities.usb488_device_capabilities = buffer[15];
+
+ kfree(buffer);
+ return 0;
+}
+
+#define capability_attribute(name) \
+static ssize_t show_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usbtmc_device_data *data = usb_get_intfdata(intf); \
+ \
+ return sprintf(buf, "%d\n", data->capabilities.name); \
+} \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+capability_attribute(interface_capabilities);
+capability_attribute(device_capabilities);
+capability_attribute(usb488_interface_capabilities);
+capability_attribute(usb488_device_capabilities);
+
+static struct attribute *capability_attrs[] = {
+ &dev_attr_interface_capabilities.attr,
+ &dev_attr_device_capabilities.attr,
+ &dev_attr_usb488_interface_capabilities.attr,
+ &dev_attr_usb488_device_capabilities.attr,
+ NULL,
+};
+
+static struct attribute_group capability_attr_grp = {
+ .attrs = capability_attrs,
+};
+
+static ssize_t show_TermChar(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usbtmc_device_data *data = usb_get_intfdata(intf);
+
+ return sprintf(buf, "%c\n", data->TermChar);
+}
+
+static ssize_t store_TermChar(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usbtmc_device_data *data = usb_get_intfdata(intf);
+
+ if (count < 1)
+ return -EINVAL;
+ data->TermChar = buf[0];
+ return count;
+}
+static DEVICE_ATTR(TermChar, S_IRUGO, show_TermChar, store_TermChar);
+
+#define data_attribute(name) \
+static ssize_t show_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usbtmc_device_data *data = usb_get_intfdata(intf); \
+ \
+ return sprintf(buf, "%d\n", data->name); \
+} \
+static ssize_t store_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usbtmc_device_data *data = usb_get_intfdata(intf); \
+ ssize_t result; \
+ unsigned val; \
+ \
+ result = sscanf(buf, "%u\n", &val); \
+ if (result != 1) \
+ result = -EINVAL; \
+ data->name = val; \
+ if (result < 0) \
+ return result; \
+ else \
+ return count; \
+} \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, store_##name)
+
+data_attribute(TermCharEnabled);
+data_attribute(auto_abort);
+
+static struct attribute *data_attrs[] = {
+ &dev_attr_TermChar.attr,
+ &dev_attr_TermCharEnabled.attr,
+ &dev_attr_auto_abort.attr,
+ NULL,
+};
+
+static struct attribute_group data_attr_grp = {
+ .attrs = data_attrs,
+};
+
+static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
+{
+ struct device *dev;
+ u8 *buffer;
+ int rv;
+
+ dev = &data->intf->dev;
+
+ buffer = kmalloc(2, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC_REQUEST_INDICATOR_PULSE,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, 0, buffer, 0x01, USBTMC_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(dev, "usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+
+ dev_dbg(dev, "INDICATOR_PULSE returned %x\n", buffer[0]);
+
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "INDICATOR_PULSE returned %x\n", buffer[0]);
+ rv = -EPERM;
+ goto exit;
+ }
+ rv = 0;
+
+exit:
+ kfree(buffer);
+ return rv;
+}
+
+static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct usbtmc_device_data *data;
+ int retval = -EBADRQC;
+
+ data = file->private_data;
+ mutex_lock(&data->io_mutex);
+
+ switch (cmd) {
+ case USBTMC_IOCTL_CLEAR_OUT_HALT:
+ retval = usbtmc_ioctl_clear_out_halt(data);
+
+ case USBTMC_IOCTL_CLEAR_IN_HALT:
+ retval = usbtmc_ioctl_clear_in_halt(data);
+
+ case USBTMC_IOCTL_INDICATOR_PULSE:
+ retval = usbtmc_ioctl_indicator_pulse(data);
+
+ case USBTMC_IOCTL_CLEAR:
+ retval = usbtmc_ioctl_clear(data);
+
+ case USBTMC_IOCTL_ABORT_BULK_OUT:
+ retval = usbtmc_ioctl_abort_bulk_out(data);
+
+ case USBTMC_IOCTL_ABORT_BULK_IN:
+ retval = usbtmc_ioctl_abort_bulk_in(data);
+ }
+
+ mutex_unlock(&data->io_mutex);
+ return retval;
+}
+
+static struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .read = usbtmc_read,
+ .write = usbtmc_write,
+ .open = usbtmc_open,
+ .release = usbtmc_release,
+ .unlocked_ioctl = usbtmc_ioctl,
+};
+
+static struct usb_class_driver usbtmc_class = {
+ .name = "usbtmc%d",
+ .fops = &fops,
+ .minor_base = USBTMC_MINOR_BASE,
+};
+
+
+static int usbtmc_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usbtmc_device_data *data;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int n;
+ int retcode;
+
+ dev_dbg(&intf->dev, "%s called\n", __func__);
+
+ data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&intf->dev, "Unable to allocate kernel memory\n");
+ return -ENOMEM;
+ }
+
+ data->intf = intf;
+ data->id = id;
+ data->usb_dev = usb_get_dev(interface_to_usbdev(intf));
+ usb_set_intfdata(intf, data);
+ kref_init(&data->kref);
+ mutex_init(&data->io_mutex);
+
+ /* Initialize USBTMC bTag and other fields */
+ data->bTag = 1;
+ data->TermCharEnabled = 0;
+ data->TermChar = '\n';
+
+ /* USBTMC devices have only one setting, so use that */
+ iface_desc = data->intf->cur_altsetting;
+
+ /* Find bulk in endpoint */
+ for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
+ endpoint = &iface_desc->endpoint[n].desc;
+
+ if (usb_endpoint_is_bulk_in(endpoint)) {
+ data->bulk_in = endpoint->bEndpointAddress;
+ dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n",
+ data->bulk_in);
+ break;
+ }
+ }
+
+ /* Find bulk out endpoint */
+ for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
+ endpoint = &iface_desc->endpoint[n].desc;
+
+ if (usb_endpoint_is_bulk_out(endpoint)) {
+ data->bulk_out = endpoint->bEndpointAddress;
+ dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n",
+ data->bulk_out);
+ break;
+ }
+ }
+
+ retcode = get_capabilities(data);
+ if (retcode)
+ dev_err(&intf->dev, "can't read capabilities\n");
+ else
+ retcode = sysfs_create_group(&intf->dev.kobj,
+ &capability_attr_grp);
+
+ retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp);
+
+ retcode = usb_register_dev(intf, &usbtmc_class);
+ if (retcode) {
+ dev_err(&intf->dev, "Not able to get a minor"
+ " (base %u, slice default): %d\n", USBTMC_MINOR_BASE,
+ retcode);
+ goto error_register;
+ }
+ dev_dbg(&intf->dev, "Using minor number %d\n", intf->minor);
+
+ return 0;
+
+error_register:
+ sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
+ sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
+ kref_put(&data->kref, usbtmc_delete);
+ return retcode;
+}
+
+static void usbtmc_disconnect(struct usb_interface *intf)
+{
+ struct usbtmc_device_data *data;
+
+ dev_dbg(&intf->dev, "usbtmc_disconnect called\n");
+
+ data = usb_get_intfdata(intf);
+ usb_deregister_dev(intf, &usbtmc_class);
+ sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
+ sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
+ kref_put(&data->kref, usbtmc_delete);
+}
+
+static struct usb_driver usbtmc_driver = {
+ .name = "usbtmc",
+ .id_table = usbtmc_devices,
+ .probe = usbtmc_probe,
+ .disconnect = usbtmc_disconnect
+};
+
+static int __init usbtmc_init(void)
+{
+ int retcode;
+
+ retcode = usb_register(&usbtmc_driver);
+ if (retcode)
+ printk(KERN_ERR KBUILD_MODNAME": Unable to register driver\n");
+ return retcode;
+}
+module_init(usbtmc_init);
+
+static void __exit usbtmc_exit(void)
+{
+ usb_deregister(&usbtmc_driver);
+}
+module_exit(usbtmc_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index cc9f397e839..e1759d17ac5 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -134,5 +134,5 @@ config USB_OTG_BLACKLIST_HUB
If you say Y here, then Linux will refuse to enumerate
external hubs. OTG hosts are allowed to reduce hardware
and software costs by not supporting external hubs. So
- are "Emedded Hosts" that don't offer OTG support.
+ are "Embedded Hosts" that don't offer OTG support.
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 7a4fa791dc1..2bccefebff1 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -413,7 +413,8 @@ static void driver_disconnect(struct usb_interface *intf)
if (likely(ifnum < 8*sizeof(ps->ifclaimed)))
clear_bit(ifnum, &ps->ifclaimed);
else
- warn("interface number %u out of range", ifnum);
+ dev_warn(&intf->dev, "interface number %u out of range\n",
+ ifnum);
usb_set_intfdata(intf, NULL);
@@ -624,6 +625,8 @@ static int usbdev_open(struct inode *inode, struct file *file)
smp_wmb();
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
+ snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
+ current->comm);
out:
if (ret) {
kfree(ps);
@@ -1774,19 +1777,20 @@ int __init usb_devio_init(void)
retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
"usb_device");
if (retval) {
- err("unable to register minors for usb_device");
+ printk(KERN_ERR "Unable to register minors for usb_device\n");
goto out;
}
cdev_init(&usb_device_cdev, &usbdev_file_operations);
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
if (retval) {
- err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
+ printk(KERN_ERR "Unable to get usb_device major %d\n",
+ USB_DEVICE_MAJOR);
goto error_cdev;
}
#ifdef CONFIG_USB_DEVICE_CLASS
usb_classdev_class = class_create(THIS_MODULE, "usb_device");
if (IS_ERR(usb_classdev_class)) {
- err("unable to register usb_device class");
+ printk(KERN_ERR "Unable to register usb_device class\n");
retval = PTR_ERR(usb_classdev_class);
cdev_del(&usb_device_cdev);
usb_classdev_class = NULL;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 5a7fa6f0995..3d7793d9303 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1070,7 +1070,8 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
struct usb_driver *driver;
driver = to_usb_driver(intf->dev.driver);
- if (!driver->reset_resume)
+ if (!driver->reset_resume ||
+ intf->needs_remote_wakeup)
return -EOPNOTSUPP;
}
}
@@ -1609,7 +1610,8 @@ int usb_external_resume_device(struct usb_device *udev)
status = usb_resume_both(udev);
udev->last_busy = jiffies;
usb_pm_unlock(udev);
- do_unbind_rebind(udev, DO_REBIND);
+ if (status == 0)
+ do_unbind_rebind(udev, DO_REBIND);
/* Now that the device is awake, we can start trying to autosuspend
* it again. */
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 22912136fc1..946fae43d62 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -169,7 +169,8 @@ static int usb_endpoint_major_init(void)
error = alloc_chrdev_region(&dev, 0, MAX_ENDPOINT_MINORS,
"usb_endpoint");
if (error) {
- err("unable to get a dynamic major for usb endpoints");
+ printk(KERN_ERR "Unable to get a dynamic major for "
+ "usb endpoints.\n");
return error;
}
usb_endpoint_major = MAJOR(dev);
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 55f7f310924..997e659ff69 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -86,7 +86,7 @@ static int init_usb_class(void)
usb_class->class = class_create(THIS_MODULE, "usb");
if (IS_ERR(usb_class->class)) {
result = IS_ERR(usb_class->class);
- err("class_create failed for usb devices");
+ printk(KERN_ERR "class_create failed for usb devices\n");
kfree(usb_class);
usb_class = NULL;
}
@@ -115,7 +115,8 @@ int usb_major_init(void)
error = register_chrdev(USB_MAJOR, "usb", &usb_fops);
if (error)
- err("unable to get major %d for usb devices", USB_MAJOR);
+ printk(KERN_ERR "Unable to get major %d for usb devices\n",
+ USB_MAJOR);
return error;
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index c8035a8216b..fc9018e72a0 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -81,6 +81,10 @@
/*-------------------------------------------------------------------------*/
+/* Keep track of which host controller drivers are loaded */
+unsigned long usb_hcds_loaded;
+EXPORT_SYMBOL_GPL(usb_hcds_loaded);
+
/* host controllers we manage */
LIST_HEAD (usb_bus_list);
EXPORT_SYMBOL_GPL (usb_bus_list);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index e710ce04e22..2dcde61c465 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -482,4 +482,10 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
*/
extern struct rw_semaphore ehci_cf_port_reset_rwsem;
+/* Keep track of which host controller drivers are loaded */
+#define USB_UHCI_LOADED 0
+#define USB_OHCI_LOADED 1
+#define USB_EHCI_LOADED 2
+extern unsigned long usb_hcds_loaded;
+
#endif /* __KERNEL__ */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index d99963873e3..9b3f16bd12c 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -77,6 +77,7 @@ struct usb_hub {
unsigned has_indicators:1;
u8 indicator[USB_MAXCHILDREN];
struct delayed_work leds;
+ struct delayed_work init_work;
};
@@ -100,6 +101,15 @@ module_param (blinkenlights, bool, S_IRUGO);
MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs");
/*
+ * Device SATA8000 FW1.0 from DATAST0R Technology Corp requires about
+ * 10 seconds to send reply for the initial 64-byte descriptor request.
+ */
+/* 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)");
+
+/*
* As of 2.6.10 we introduce a new USB device initialization scheme which
* closely resembles the way Windows works. Hopefully it will be compatible
* with a wider range of devices than the old scheme. However some previously
@@ -515,10 +525,14 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
}
EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer);
-static void hub_power_on(struct usb_hub *hub)
+/* If do_delay is false, return the number of milliseconds the caller
+ * needs to delay.
+ */
+static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
{
int port1;
unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
+ unsigned delay;
u16 wHubCharacteristics =
le16_to_cpu(hub->descriptor->wHubCharacteristics);
@@ -537,7 +551,10 @@ static void hub_power_on(struct usb_hub *hub)
set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
/* Wait at least 100 msec for power to become stable */
- msleep(max(pgood_delay, (unsigned) 100));
+ delay = max(pgood_delay, (unsigned) 100);
+ if (do_delay)
+ msleep(delay);
+ return delay;
}
static int hub_hub_status(struct usb_hub *hub,
@@ -599,21 +616,55 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
}
enum hub_activation_type {
- HUB_INIT, HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME
+ HUB_INIT, HUB_INIT2, HUB_INIT3,
+ HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME,
};
+static void hub_init_func2(struct work_struct *ws);
+static void hub_init_func3(struct work_struct *ws);
+
static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
{
struct usb_device *hdev = hub->hdev;
int port1;
int status;
bool need_debounce_delay = false;
+ unsigned delay;
+
+ /* Continue a partial initialization */
+ if (type == HUB_INIT2)
+ goto init2;
+ if (type == HUB_INIT3)
+ goto init3;
/* After a resume, port power should still be on.
* For any other type of activation, turn it on.
*/
- if (type != HUB_RESUME)
- hub_power_on(hub);
+ if (type != HUB_RESUME) {
+
+ /* Speed up system boot by using a delayed_work for the
+ * hub's initial power-up delays. This is pretty awkward
+ * and the implementation looks like a home-brewed sort of
+ * setjmp/longjmp, but it saves at least 100 ms for each
+ * root hub (assuming usbcore is compiled into the kernel
+ * rather than as a module). It adds up.
+ *
+ * This can't be done for HUB_RESUME or HUB_RESET_RESUME
+ * because for those activation types the ports have to be
+ * operational when we return. In theory this could be done
+ * for HUB_POST_RESET, but it's easier not to.
+ */
+ if (type == HUB_INIT) {
+ delay = hub_power_on(hub, false);
+ PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2);
+ schedule_delayed_work(&hub->init_work,
+ msecs_to_jiffies(delay));
+ return; /* Continues at init2: below */
+ } else {
+ hub_power_on(hub, true);
+ }
+ }
+ init2:
/* Check each port and set hub->change_bits to let khubd know
* which ports need attention.
@@ -692,9 +743,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
* If any port-status changes do occur during this delay, khubd
* will see them later and handle them normally.
*/
- if (need_debounce_delay)
- msleep(HUB_DEBOUNCE_STABLE);
-
+ if (need_debounce_delay) {
+ delay = HUB_DEBOUNCE_STABLE;
+
+ /* Don't do a long sleep inside a workqueue routine */
+ if (type == HUB_INIT2) {
+ PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3);
+ schedule_delayed_work(&hub->init_work,
+ msecs_to_jiffies(delay));
+ return; /* Continues at init3: below */
+ } else {
+ msleep(delay);
+ }
+ }
+ init3:
hub->quiescing = 0;
status = usb_submit_urb(hub->urb, GFP_NOIO);
@@ -707,6 +769,21 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
kick_khubd(hub);
}
+/* Implement the continuations for the delays above */
+static void hub_init_func2(struct work_struct *ws)
+{
+ struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
+
+ hub_activate(hub, HUB_INIT2);
+}
+
+static void hub_init_func3(struct work_struct *ws)
+{
+ struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
+
+ hub_activate(hub, HUB_INIT3);
+}
+
enum hub_quiescing_type {
HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND
};
@@ -716,6 +793,8 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
struct usb_device *hdev = hub->hdev;
int i;
+ cancel_delayed_work_sync(&hub->init_work);
+
/* khubd and related activity won't re-trigger */
hub->quiescing = 1;
@@ -1099,6 +1178,7 @@ descriptor_error:
hub->intfdev = &intf->dev;
hub->hdev = hdev;
INIT_DELAYED_WORK(&hub->leds, led_work);
+ INIT_DELAYED_WORK(&hub->init_work, NULL);
usb_get_intf(intf);
usb_set_intfdata (intf, hub);
@@ -2467,7 +2547,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
USB_DT_DEVICE << 8, 0,
buf, GET_DESCRIPTOR_BUFSIZE,
- USB_CTRL_GET_TIMEOUT);
+ initial_descriptor_timeout);
switch (buf->bMaxPacketSize0) {
case 8: case 16: case 32: case 64: case 255:
if (buf->bDescriptorType ==
@@ -3035,7 +3115,7 @@ static void hub_events(void)
i);
clear_port_feature(hdev, i,
USB_PORT_FEAT_C_OVER_CURRENT);
- hub_power_on(hub);
+ hub_power_on(hub, true);
}
if (portchange & USB_PORT_STAT_C_RESET) {
@@ -3070,7 +3150,7 @@ static void hub_events(void)
dev_dbg (hub_dev, "overcurrent change\n");
msleep(500); /* Cool down */
clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
- hub_power_on(hub);
+ hub_power_on(hub, true);
}
}
@@ -3424,7 +3504,7 @@ int usb_reset_device(struct usb_device *udev)
USB_INTERFACE_BOUND)
rebind = 1;
}
- if (rebind)
+ if (ret == 0 && rebind)
usb_rebind_intf(cintf);
}
}
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 77fa7a08080..94632264dcc 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -180,8 +180,8 @@ static int parse_options(struct super_block *s, char *data)
listmode = option & S_IRWXUGO;
break;
default:
- err("usbfs: unrecognised mount option \"%s\" "
- "or missing value\n", p);
+ printk(KERN_ERR "usbfs: unrecognised mount option "
+ "\"%s\" or missing value\n", p);
return -EINVAL;
}
}
@@ -240,7 +240,9 @@ static void update_sb(struct super_block *sb)
update_special(bus);
break;
default:
- warn("Unknown node %s mode %x found on remount!\n",bus->d_name.name,bus->d_inode->i_mode);
+ printk(KERN_WARNING "usbfs: Unknown node %s "
+ "mode %x found on remount!\n",
+ bus->d_name.name, bus->d_inode->i_mode);
break;
}
}
@@ -259,7 +261,7 @@ static int remount(struct super_block *sb, int *flags, char *data)
return 0;
if (parse_options(sb, data)) {
- warn("usbfs: mount parameter error:");
+ printk(KERN_WARNING "usbfs: mount parameter error.\n");
return -EINVAL;
}
@@ -599,7 +601,7 @@ static int create_special_files (void)
/* create the devices special file */
retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
if (retval) {
- err ("Unable to get usbfs mount");
+ printk(KERN_ERR "Unable to get usbfs mount\n");
goto exit;
}
@@ -611,7 +613,7 @@ static int create_special_files (void)
NULL, &usbfs_devices_fops,
listuid, listgid);
if (devices_usbfs_dentry == NULL) {
- err ("Unable to create devices usbfs file");
+ printk(KERN_ERR "Unable to create devices usbfs file\n");
retval = -ENODEV;
goto error_clean_mounts;
}
@@ -663,7 +665,7 @@ static void usbfs_add_bus(struct usb_bus *bus)
bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent,
bus, NULL, busuid, busgid);
if (bus->usbfs_dentry == NULL) {
- err ("error creating usbfs bus entry");
+ printk(KERN_ERR "Error creating usbfs bus entry\n");
return;
}
}
@@ -694,7 +696,7 @@ static void usbfs_add_device(struct usb_device *dev)
&usbdev_file_operations,
devuid, devgid);
if (dev->usbfs_dentry == NULL) {
- err ("error creating usbfs device entry");
+ printk(KERN_ERR "Error creating usbfs device entry\n");
return;
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 286b4431a09..887738577b2 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1204,7 +1204,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
alt = usb_altnum_to_altsetting(iface, alternate);
if (!alt) {
- warn("selecting invalid altsetting %d", alternate);
+ dev_warn(&dev->dev, "selecting invalid altsetting %d",
+ alternate);
return -EINVAL;
}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 5e1f5d55bf0..f66fba11fbd 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -743,6 +743,29 @@ static ssize_t show_modalias(struct device *dev,
}
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+static ssize_t show_supports_autosuspend(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf;
+ struct usb_device *udev;
+ int ret;
+
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
+
+ usb_lock_device(udev);
+ /* Devices will be autosuspended even when an interface isn't claimed */
+ if (!intf->dev.driver ||
+ to_usb_driver(intf->dev.driver)->supports_autosuspend)
+ ret = sprintf(buf, "%u\n", 1);
+ else
+ ret = sprintf(buf, "%u\n", 0);
+ usb_unlock_device(udev);
+
+ return ret;
+}
+static DEVICE_ATTR(supports_autosuspend, S_IRUGO, show_supports_autosuspend, NULL);
+
static struct attribute *intf_attrs[] = {
&dev_attr_bInterfaceNumber.attr,
&dev_attr_bAlternateSetting.attr,
@@ -751,6 +774,7 @@ static struct attribute *intf_attrs[] = {
&dev_attr_bInterfaceSubClass.attr,
&dev_attr_bInterfaceProtocol.attr,
&dev_attr_modalias.attr,
+ &dev_attr_supports_autosuspend.attr,
NULL,
};
static struct attribute_group intf_attr_grp = {
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 47111e88f79..f2638009a46 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -10,6 +10,8 @@
#define to_urb(d) container_of(d, struct urb, kref)
+static DEFINE_SPINLOCK(usb_reject_lock);
+
static void urb_destroy(struct kref *kref)
{
struct urb *urb = to_urb(kref);
@@ -68,7 +70,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
- err("alloc_urb: kmalloc failed");
+ printk(KERN_ERR "alloc_urb: kmalloc failed\n");
return NULL;
}
usb_init_urb(urb);
@@ -127,6 +129,13 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
usb_get_urb(urb);
list_add_tail(&urb->anchor_list, &anchor->urb_list);
urb->anchor = anchor;
+
+ if (unlikely(anchor->poisoned)) {
+ spin_lock(&usb_reject_lock);
+ urb->reject++;
+ spin_unlock(&usb_reject_lock);
+ }
+
spin_unlock_irqrestore(&anchor->lock, flags);
}
EXPORT_SYMBOL_GPL(usb_anchor_urb);
@@ -398,7 +407,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* fail if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) {
- err("BOGUS urb flags, %x --> %x",
+ dev_err(&dev->dev, "BOGUS urb flags, %x --> %x\n",
orig_flags, urb->transfer_flags);
return -EINVAL;
}
@@ -544,25 +553,70 @@ EXPORT_SYMBOL_GPL(usb_unlink_urb);
*/
void usb_kill_urb(struct urb *urb)
{
- static DEFINE_MUTEX(reject_mutex);
-
might_sleep();
if (!(urb && urb->dev && urb->ep))
return;
- mutex_lock(&reject_mutex);
+ spin_lock_irq(&usb_reject_lock);
++urb->reject;
- mutex_unlock(&reject_mutex);
+ spin_unlock_irq(&usb_reject_lock);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
- mutex_lock(&reject_mutex);
+ spin_lock_irq(&usb_reject_lock);
--urb->reject;
- mutex_unlock(&reject_mutex);
+ spin_unlock_irq(&usb_reject_lock);
}
EXPORT_SYMBOL_GPL(usb_kill_urb);
/**
+ * usb_poison_urb - reliably kill a transfer and prevent further use of an URB
+ * @urb: pointer to URB describing a previously submitted request,
+ * may be NULL
+ *
+ * This routine cancels an in-progress request. It is guaranteed that
+ * upon return all completion handlers will have finished and the URB
+ * will be totally idle and cannot be reused. These features make
+ * this an ideal way to stop I/O in a disconnect() callback.
+ * If the request has not already finished or been unlinked
+ * the completion handler will see urb->status == -ENOENT.
+ *
+ * After and while the routine runs, attempts to resubmit the URB will fail
+ * with error -EPERM. Thus even if the URB's completion handler always
+ * tries to resubmit, it will not succeed and the URB will become idle.
+ *
+ * This routine may not be used in an interrupt context (such as a bottom
+ * half or a completion handler), or when holding a spinlock, or in other
+ * situations where the caller can't schedule().
+ */
+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);
+
+ usb_hcd_unlink_urb(urb, -ENOENT);
+ wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
+}
+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);
+}
+EXPORT_SYMBOL_GPL(usb_unpoison_urb);
+
+/**
* usb_kill_anchored_urbs - cancel transfer requests en masse
* @anchor: anchor the requests are bound to
*
@@ -589,6 +643,35 @@ void usb_kill_anchored_urbs(struct usb_anchor *anchor)
}
EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
+
+/**
+ * usb_poison_anchored_urbs - cease all traffic from an anchor
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be poisoned starting
+ * from the back of the queue. Newly added URBs will also be
+ * poisoned
+ */
+void usb_poison_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+
+ spin_lock_irq(&anchor->lock);
+ anchor->poisoned = 1;
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev, struct urb,
+ anchor_list);
+ /* we must make sure the URB isn't freed before we kill it*/
+ usb_get_urb(victim);
+ spin_unlock_irq(&anchor->lock);
+ /* this will unanchor the URB */
+ usb_poison_urb(victim);
+ usb_put_urb(victim);
+ spin_lock_irq(&anchor->lock);
+ }
+ spin_unlock_irq(&anchor->lock);
+}
+EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs);
/**
* usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse
* @anchor: anchor the requests are bound to
@@ -633,3 +716,73 @@ int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
msecs_to_jiffies(timeout));
}
EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
+
+/**
+ * usb_get_from_anchor - get an anchor's oldest urb
+ * @anchor: the anchor whose urb you want
+ *
+ * this will take the oldest urb from an anchor,
+ * unanchor and return it
+ */
+struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+ unsigned long flags;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ if (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.next, struct urb,
+ anchor_list);
+ usb_get_urb(victim);
+ spin_unlock_irqrestore(&anchor->lock, flags);
+ usb_unanchor_urb(victim);
+ } else {
+ spin_unlock_irqrestore(&anchor->lock, flags);
+ victim = NULL;
+ }
+
+ return victim;
+}
+
+EXPORT_SYMBOL_GPL(usb_get_from_anchor);
+
+/**
+ * usb_scuttle_anchored_urbs - unanchor all an anchor's urbs
+ * @anchor: the anchor whose urbs you want to unanchor
+ *
+ * use this to get rid of all an anchor's urbs
+ */
+void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+ unsigned long flags;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev, struct urb,
+ anchor_list);
+ usb_get_urb(victim);
+ spin_unlock_irqrestore(&anchor->lock, flags);
+ /* this may free the URB */
+ usb_unanchor_urb(victim);
+ usb_put_urb(victim);
+ spin_lock_irqsave(&anchor->lock, flags);
+ }
+ spin_unlock_irqrestore(&anchor->lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs);
+
+/**
+ * usb_anchor_empty - is an anchor empty
+ * @anchor: the anchor you want to query
+ *
+ * returns 1 if the anchor has no urbs associated with it
+ */
+int usb_anchor_empty(struct usb_anchor *anchor)
+{
+ return list_empty(&anchor->urb_list);
+}
+
+EXPORT_SYMBOL_GPL(usb_anchor_empty);
+
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index acc95b2ac6f..dd4cd5a5137 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -45,7 +45,7 @@ if USB_GADGET
config USB_GADGET_DEBUG
boolean "Debugging messages (DEVELOPMENT)"
- depends on USB_GADGET && DEBUG_KERNEL
+ depends on DEBUG_KERNEL
help
Many controller and gadget drivers will print some debugging
messages if you use this option to ask for those messages.
@@ -59,7 +59,7 @@ config USB_GADGET_DEBUG
config USB_GADGET_DEBUG_FILES
boolean "Debugging information files (DEVELOPMENT)"
- depends on USB_GADGET && PROC_FS
+ depends on PROC_FS
help
Some of the drivers in the "gadget" framework can expose
debugging information in files such as /proc/driver/udc
@@ -70,7 +70,7 @@ config USB_GADGET_DEBUG_FILES
config USB_GADGET_DEBUG_FS
boolean "Debugging information files in debugfs (DEVELOPMENT)"
- depends on USB_GADGET && DEBUG_FS
+ depends on DEBUG_FS
help
Some of the drivers in the "gadget" framework can expose
debugging information in files under /sys/kernel/debug/.
@@ -79,12 +79,36 @@ config USB_GADGET_DEBUG_FS
Enable these files by choosing "Y" here. If in doubt, or
to conserve kernel memory, say "N".
+config USB_GADGET_VBUS_DRAW
+ int "Maximum VBUS Power usage (2-500 mA)"
+ range 2 500
+ default 2
+ help
+ Some devices need to draw power from USB when they are
+ configured, perhaps to operate circuitry or to recharge
+ batteries. This is in addition to any local power supply,
+ such as an AC adapter or batteries.
+
+ Enter the maximum power your device draws through USB, in
+ milliAmperes. The permitted range of values is 2 - 500 mA;
+ 0 mA would be legal, but can make some hosts misbehave.
+
+ This value will be used except for system-specific gadget
+ drivers that have more specific information.
+
config USB_GADGET_SELECTED
boolean
#
# USB Peripheral Controller Support
#
+# The order here is alphabetical, except that integrated controllers go
+# before discrete ones so they will be the initial/default value:
+# - integrated/SOC controllers first
+# - licensed IP used in both SOC and discrete versions
+# - discrete ones (including all PCI-only controllers)
+# - debug/dummy gadget+hcd is last.
+#
choice
prompt "USB Peripheral Controller"
depends on USB_GADGET
@@ -94,26 +118,27 @@ choice
Many controller drivers are platform-specific; these
often need board-specific hooks.
-config USB_GADGET_AMD5536UDC
- boolean "AMD5536 UDC"
- depends on PCI
- select USB_GADGET_DUALSPEED
+#
+# Integrated controllers
+#
+
+config USB_GADGET_AT91
+ boolean "Atmel AT91 USB Device Port"
+ depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9
+ select USB_GADGET_SELECTED
help
- The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
- It is a USB Highspeed DMA capable USB device controller. Beside ep0
- it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
- The UDC port supports OTG operation, and may be used as a host port
- if it's not being used to implement peripheral or OTG roles.
+ Many Atmel AT91 processors (such as the AT91RM2000) have a
+ full speed USB Device Port with support for five configurable
+ endpoints (plus endpoint zero).
Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "amd5536udc" and force all
+ dynamically linked module called "at91_udc" and force all
gadget drivers to also be dynamically linked.
-config USB_AMD5536UDC
+config USB_AT91
tristate
- depends on USB_GADGET_AMD5536UDC
+ depends on USB_GADGET_AT91
default USB_GADGET
- select USB_GADGET_SELECTED
config USB_GADGET_ATMEL_USBA
boolean "Atmel USBA"
@@ -150,28 +175,50 @@ config USB_FSL_USB2
default USB_GADGET
select USB_GADGET_SELECTED
-config USB_GADGET_NET2280
- boolean "NetChip 228x"
- depends on PCI
- select USB_GADGET_DUALSPEED
+config USB_GADGET_LH7A40X
+ boolean "LH7A40X"
+ depends on ARCH_LH7A40X
help
- NetChip 2280 / 2282 is a PCI based USB peripheral controller which
- supports both full and high speed USB 2.0 data transfers.
-
- It has six configurable endpoints, as well as endpoint zero
- (for control transfers) and several endpoints with dedicated
- functions.
+ This driver provides USB Device Controller driver for LH7A40x
+
+config USB_LH7A40X
+ tristate
+ depends on USB_GADGET_LH7A40X
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_GADGET_OMAP
+ boolean "OMAP USB Device Controller"
+ depends on ARCH_OMAP
+ select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
+ help
+ Many Texas Instruments OMAP processors have flexible full
+ speed USB device controllers, with support for up to 30
+ endpoints (plus endpoint zero). This driver supports the
+ controller in the OMAP 1611, and should work with controllers
+ in other OMAP processors too, given minor tweaks.
Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "net2280" and force all
+ dynamically linked module called "omap_udc" and force all
gadget drivers to also be dynamically linked.
-config USB_NET2280
+config USB_OMAP
tristate
- depends on USB_GADGET_NET2280
+ depends on USB_GADGET_OMAP
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_OTG
+ boolean "OTG Support"
+ depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD
+ help
+ The most notable feature of USB OTG is support for a
+ "Dual-Role" device, which can act as either a device
+ or a host. The initial role choice can be changed
+ later, when two dual-role devices talk to each other.
+
+ Select this only if your OMAP board has a Mini-AB connector.
+
config USB_GADGET_PXA25X
boolean "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
@@ -203,34 +250,6 @@ config USB_PXA25X_SMALL
default y if USB_ETH
default y if USB_G_SERIAL
-config USB_GADGET_M66592
- boolean "Renesas M66592 USB Peripheral Controller"
- select USB_GADGET_DUALSPEED
- help
- M66592 is a discrete USB peripheral controller chip that
- supports both full and high speed USB 2.0 data transfers.
- It has seven configurable endpoints, and endpoint zero.
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "m66592_udc" and force all
- gadget drivers to also be dynamically linked.
-
-config USB_M66592
- tristate
- depends on USB_GADGET_M66592
- default USB_GADGET
- select USB_GADGET_SELECTED
-
-config SUPERH_BUILT_IN_M66592
- boolean "Enable SuperH built-in USB like the M66592"
- depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722
- help
- SH7722 has USB like the M66592.
-
- The transfer rate is very slow when use "Ethernet Gadget".
- However, this problem is improved if change a value of
- NET_IP_ALIGN to 4.
-
config USB_GADGET_PXA27X
boolean "PXA 27x"
depends on ARCH_PXA && PXA27x
@@ -251,40 +270,32 @@ config USB_PXA27X
default USB_GADGET
select USB_GADGET_SELECTED
-config USB_GADGET_GOKU
- boolean "Toshiba TC86C001 'Goku-S'"
- depends on PCI
+config USB_GADGET_S3C2410
+ boolean "S3C2410 USB Device Controller"
+ depends on ARCH_S3C2410
help
- The Toshiba TC86C001 is a PCI device which includes controllers
- for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI).
-
- The device controller has three configurable (bulk or interrupt)
- endpoints, plus endpoint zero (for control transfers).
+ Samsung's S3C2410 is an ARM-4 processor with an integrated
+ full speed USB 1.1 device controller. It has 4 configurable
+ 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 "goku_udc" and to force all
- gadget drivers to also be dynamically linked.
+ This driver has been tested on the S3C2410, S3C2412, and
+ S3C2440 processors.
-config USB_GOKU
+config USB_S3C2410
tristate
- depends on USB_GADGET_GOKU
+ depends on USB_GADGET_S3C2410
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_S3C2410_DEBUG
+ boolean "S3C2410 udc debug messages"
+ depends on USB_GADGET_S3C2410
-config USB_GADGET_LH7A40X
- boolean "LH7A40X"
- depends on ARCH_LH7A40X
- help
- This driver provides USB Device Controller driver for LH7A40x
-
-config USB_LH7A40X
- tristate
- depends on USB_GADGET_LH7A40X
- default USB_GADGET
- select USB_GADGET_SELECTED
+#
+# Controllers available in both integrated and discrete versions
+#
-# built in ../musb along with host support
+# musb builds in ../musb along with host support
config USB_GADGET_MUSB_HDRC
boolean "Inventra HDRC USB Peripheral (TI, ...)"
depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
@@ -294,76 +305,124 @@ config USB_GADGET_MUSB_HDRC
This OTG-capable silicon IP is used in dual designs including
the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
-config USB_GADGET_OMAP
- boolean "OMAP USB Device Controller"
- depends on ARCH_OMAP
- select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+config USB_GADGET_M66592
+ boolean "Renesas M66592 USB Peripheral Controller"
+ select USB_GADGET_DUALSPEED
help
- Many Texas Instruments OMAP processors have flexible full
- speed USB device controllers, with support for up to 30
- endpoints (plus endpoint zero). This driver supports the
- controller in the OMAP 1611, and should work with controllers
- in other OMAP processors too, given minor tweaks.
+ M66592 is a discrete USB peripheral controller chip that
+ supports both full and high speed USB 2.0 data transfers.
+ It has seven configurable endpoints, and endpoint zero.
Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "omap_udc" and force all
+ dynamically linked module called "m66592_udc" and force all
gadget drivers to also be dynamically linked.
-config USB_OMAP
+config USB_M66592
tristate
- depends on USB_GADGET_OMAP
+ depends on USB_GADGET_M66592
default USB_GADGET
select USB_GADGET_SELECTED
-config USB_OTG
- boolean "OTG Support"
- depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD
+config SUPERH_BUILT_IN_M66592
+ boolean "Enable SuperH built-in USB like the M66592"
+ depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722
help
- The most notable feature of USB OTG is support for a
- "Dual-Role" device, which can act as either a device
- or a host. The initial role choice can be changed
- later, when two dual-role devices talk to each other.
+ SH7722 has USB like the M66592.
- Select this only if your OMAP board has a Mini-AB connector.
+ The transfer rate is very slow when use "Ethernet Gadget".
+ However, this problem is improved if change a value of
+ NET_IP_ALIGN to 4.
-config USB_GADGET_S3C2410
- boolean "S3C2410 USB Device Controller"
- depends on ARCH_S3C2410
+#
+# Controllers available only in discrete form (and all PCI controllers)
+#
+
+config USB_GADGET_AMD5536UDC
+ boolean "AMD5536 UDC"
+ depends on PCI
+ select USB_GADGET_DUALSPEED
help
- Samsung's S3C2410 is an ARM-4 processor with an integrated
- full speed USB 1.1 device controller. It has 4 configurable
- endpoints, as well as endpoint zero (for control transfers).
+ The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
+ It is a USB Highspeed DMA capable USB device controller. Beside ep0
+ it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ The UDC port supports OTG operation, and may be used as a host port
+ if it's not being used to implement peripheral or OTG roles.
- This driver has been tested on the S3C2410, S3C2412, and
- S3C2440 processors.
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "amd5536udc" and force all
+ gadget drivers to also be dynamically linked.
-config USB_S3C2410
+config USB_AMD5536UDC
tristate
- depends on USB_GADGET_S3C2410
+ depends on USB_GADGET_AMD5536UDC
default USB_GADGET
select USB_GADGET_SELECTED
-config USB_S3C2410_DEBUG
- boolean "S3C2410 udc debug messages"
- depends on USB_GADGET_S3C2410
+config USB_GADGET_FSL_QE
+ boolean "Freescale QE/CPM USB Device Controller"
+ depends on FSL_SOC && (QUICC_ENGINE || CPM)
+ help
+ Some of Freescale PowerPC processors have a Full Speed
+ QE/CPM2 USB controller, which support device mode with 4
+ programmable endpoints. This driver supports the
+ controller in the MPC8360 and MPC8272, and should work with
+ controllers having QE or CPM2, given minor tweaks.
-config USB_GADGET_AT91
- boolean "AT91 USB Device Port"
- depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9
+ Set CONFIG_USB_GADGET to "m" to build this driver as a
+ dynmically linked module called "fsl_qe_udc".
+
+config USB_FSL_QE
+ tristate
+ depends on USB_GADGET_FSL_QE
+ default USB_GADGET
select USB_GADGET_SELECTED
+
+config USB_GADGET_NET2280
+ boolean "NetChip 228x"
+ depends on PCI
+ select USB_GADGET_DUALSPEED
help
- Many Atmel AT91 processors (such as the AT91RM2000) have a
- full speed USB Device Port with support for five configurable
- endpoints (plus endpoint zero).
+ NetChip 2280 / 2282 is a PCI based USB peripheral controller which
+ supports both full and high speed USB 2.0 data transfers.
+
+ It has six configurable endpoints, as well as endpoint zero
+ (for control transfers) and several endpoints with dedicated
+ functions.
Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "at91_udc" and force all
+ dynamically linked module called "net2280" and force all
gadget drivers to also be dynamically linked.
-config USB_AT91
+config USB_NET2280
tristate
- depends on USB_GADGET_AT91
+ depends on USB_GADGET_NET2280
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_GADGET_GOKU
+ boolean "Toshiba TC86C001 'Goku-S'"
+ depends on PCI
+ help
+ The Toshiba TC86C001 is a PCI device which includes controllers
+ for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI).
+
+ The device controller has three configurable (bulk or interrupt)
+ endpoints, plus endpoint zero (for control transfers).
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "goku_udc" and to force all
+ gadget drivers to also be dynamically linked.
+
+config USB_GOKU
+ tristate
+ depends on USB_GADGET_GOKU
default USB_GADGET
+ select USB_GADGET_SELECTED
+
+
+#
+# LAST -- dummy/emulated controller
+#
config USB_GADGET_DUMMY_HCD
boolean "Dummy HCD (DEVELOPMENT)"
@@ -553,19 +612,23 @@ config USB_FILE_STORAGE_TEST
normal operation.
config USB_G_SERIAL
- tristate "Serial Gadget (with CDC ACM support)"
+ tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
help
The Serial Gadget talks to the Linux-USB generic serial driver.
This driver supports a CDC-ACM module option, which can be used
to interoperate with MS-Windows hosts or with the Linux-USB
"cdc-acm" driver.
+ This driver also supports a CDC-OBEX option. You will need a
+ user space OBEX server talking to /dev/ttyGS*, since the kernel
+ itself doesn't implement the OBEX protocol.
+
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_serial".
For more information, see Documentation/usb/gadget_serial.txt
which includes instructions and a "driver info file" needed to
- make MS-Windows work with this driver.
+ make MS-Windows work with CDC ACM.
config USB_MIDI_GADGET
tristate "MIDI Gadget (EXPERIMENTAL)"
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 2267fa0b51b..bd4041b47dc 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o
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
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
index a724fc14985..5495b171cf2 100644
--- a/drivers/usb/gadget/cdc2.c
+++ b/drivers/usb/gadget/cdc2.c
@@ -155,7 +155,6 @@ static struct usb_configuration cdc_config_driver = {
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1, /* 2 mA, minimal */
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 85c876c1f15..f2da0269e1b 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -128,6 +128,70 @@ done:
}
/**
+ * usb_function_deactivate - prevent function and gadget enumeration
+ * @function: the function that isn't yet ready to respond
+ *
+ * Blocks response of the gadget driver to host enumeration by
+ * preventing the data line pullup from being activated. This is
+ * normally called during @bind() processing to change from the
+ * initial "ready to respond" state, or when a required resource
+ * becomes available.
+ *
+ * For example, drivers that serve as a passthrough to a userspace
+ * daemon can block enumeration unless that daemon (such as an OBEX,
+ * MTP, or print server) is ready to handle host requests.
+ *
+ * Not all systems support software control of their USB peripheral
+ * data pullups.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_deactivate(struct usb_function *function)
+{
+ struct usb_composite_dev *cdev = function->config->cdev;
+ int status = 0;
+
+ spin_lock(&cdev->lock);
+
+ if (cdev->deactivations == 0)
+ status = usb_gadget_disconnect(cdev->gadget);
+ if (status == 0)
+ cdev->deactivations++;
+
+ spin_unlock(&cdev->lock);
+ return status;
+}
+
+/**
+ * usb_function_activate - allow function and gadget enumeration
+ * @function: function on which usb_function_activate() was called
+ *
+ * Reverses effect of usb_function_deactivate(). If no more functions
+ * are delaying their activation, the gadget driver will respond to
+ * host enumeration procedures.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_activate(struct usb_function *function)
+{
+ struct usb_composite_dev *cdev = function->config->cdev;
+ int status = 0;
+
+ spin_lock(&cdev->lock);
+
+ if (WARN_ON(cdev->deactivations == 0))
+ status = -EINVAL;
+ else {
+ cdev->deactivations--;
+ if (cdev->deactivations == 0)
+ status = usb_gadget_connect(cdev->gadget);
+ }
+
+ spin_unlock(&cdev->lock);
+ return status;
+}
+
+/**
* usb_interface_id() - allocate an unused interface ID
* @config: configuration associated with the interface
* @function: function handling the interface
@@ -181,7 +245,7 @@ static int config_buf(struct usb_configuration *config,
c->bConfigurationValue = config->bConfigurationValue;
c->iConfiguration = config->iConfiguration;
c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
- c->bMaxPower = config->bMaxPower;
+ c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2);
/* There may be e.g. OTG descriptors */
if (config->descriptors) {
@@ -368,7 +432,7 @@ static int set_config(struct usb_composite_dev *cdev,
}
/* when we return, be sure our power usage is valid */
- power = 2 * c->bMaxPower;
+ power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
done:
usb_gadget_vbus_draw(gadget, power);
return result;
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 1ca1c326392..e1191b9a316 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -168,7 +168,7 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
* usb_find_endpoint - find a copy of an endpoint descriptor
* @src: original vector of descriptors
* @copy: copy of @src
- * @ep: endpoint descriptor found in @src
+ * @match: endpoint descriptor found in @src
*
* This returns the copy of the @match descriptor made for @copy. Its
* intended use is to help remembering the endpoint descriptor to use
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 7600a0c7875..9064696636a 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -82,6 +82,7 @@ struct dummy_ep {
const struct usb_endpoint_descriptor *desc;
struct usb_ep ep;
unsigned halted : 1;
+ unsigned wedged : 1;
unsigned already_seen : 1;
unsigned setup_stage : 1;
};
@@ -436,6 +437,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
/* at this point real hardware should be NAKing transfers
* to that endpoint, until a buffer is queued to it.
*/
+ ep->halted = ep->wedged = 0;
retval = 0;
done:
return retval;
@@ -597,7 +599,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
}
static int
-dummy_set_halt (struct usb_ep *_ep, int value)
+dummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
{
struct dummy_ep *ep;
struct dummy *dum;
@@ -609,16 +611,32 @@ dummy_set_halt (struct usb_ep *_ep, int value)
if (!dum->driver)
return -ESHUTDOWN;
if (!value)
- ep->halted = 0;
+ ep->halted = ep->wedged = 0;
else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
!list_empty (&ep->queue))
return -EAGAIN;
- else
+ else {
ep->halted = 1;
+ if (wedged)
+ ep->wedged = 1;
+ }
/* FIXME clear emulated data toggle too */
return 0;
}
+static int
+dummy_set_halt(struct usb_ep *_ep, int value)
+{
+ return dummy_set_halt_and_wedge(_ep, value, 0);
+}
+
+static int dummy_set_wedge(struct usb_ep *_ep)
+{
+ if (!_ep || _ep->name == ep0name)
+ return -EINVAL;
+ return dummy_set_halt_and_wedge(_ep, 1, 1);
+}
+
static const struct usb_ep_ops dummy_ep_ops = {
.enable = dummy_enable,
.disable = dummy_disable,
@@ -630,6 +648,7 @@ static const struct usb_ep_ops dummy_ep_ops = {
.dequeue = dummy_dequeue,
.set_halt = dummy_set_halt,
+ .set_wedge = dummy_set_wedge,
};
/*-------------------------------------------------------------------------*/
@@ -760,7 +779,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
ep->ep.name = ep_name [i];
ep->ep.ops = &dummy_ep_ops;
list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list);
- ep->halted = ep->already_seen = ep->setup_stage = 0;
+ ep->halted = ep->wedged = ep->already_seen =
+ ep->setup_stage = 0;
ep->ep.maxpacket = ~0;
ep->last_io = jiffies;
ep->gadget = &dum->gadget;
@@ -1351,7 +1371,7 @@ restart:
} else if (setup.bRequestType == Ep_Request) {
// endpoint halt
ep2 = find_endpoint (dum, w_index);
- if (!ep2) {
+ if (!ep2 || ep2->ep.name == ep0name) {
value = -EOPNOTSUPP;
break;
}
@@ -1380,7 +1400,8 @@ restart:
value = -EOPNOTSUPP;
break;
}
- ep2->halted = 0;
+ if (!ep2->wedged)
+ ep2->halted = 0;
value = 0;
status = 0;
}
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 944c8e889ab..37252d0012a 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -242,7 +242,6 @@ static struct usb_configuration rndis_config_driver = {
.bConfigurationValue = 2,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1, /* 2 mA, minimal */
};
/*-------------------------------------------------------------------------*/
@@ -271,7 +270,6 @@ static struct usb_configuration eth_config_driver = {
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1, /* 2 mA, minimal */
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index 87dde012dac..8affe1dfc2c 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -352,7 +352,6 @@ static struct usb_configuration loopback_driver = {
.bind = loopback_bind_config,
.bConfigurationValue = 2,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1, /* 2 mA, minimal */
/* .iConfiguration = DYNAMIC */
};
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
new file mode 100644
index 00000000000..80c2e7e9622
--- /dev/null
+++ b/drivers/usb/gadget/f_obex.c
@@ -0,0 +1,493 @@
+/*
+ * f_obex.c -- USB CDC OBEX function driver
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * Based on f_acm.c by Al Borchers and David Brownell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+
+#include "u_serial.h"
+#include "gadget_chips.h"
+
+
+/*
+ * This CDC OBEX function support just packages a TTY-ish byte stream.
+ * A user mode server will put it into "raw" mode and handle all the
+ * relevant protocol details ... this is just a kernel passthrough.
+ * When possible, we prevent gadget enumeration until that server is
+ * ready to handle the commands.
+ */
+
+struct obex_ep_descs {
+ struct usb_endpoint_descriptor *obex_in;
+ struct usb_endpoint_descriptor *obex_out;
+};
+
+struct f_obex {
+ struct gserial port;
+ u8 ctrl_id;
+ u8 data_id;
+ u8 port_num;
+ u8 can_activate;
+
+ struct obex_ep_descs fs;
+ struct obex_ep_descs hs;
+};
+
+static inline struct f_obex *func_to_obex(struct usb_function *f)
+{
+ return container_of(f, struct f_obex, port.func);
+}
+
+static inline struct f_obex *port_to_obex(struct gserial *p)
+{
+ return container_of(p, struct f_obex, port);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define OBEX_CTRL_IDX 0
+#define OBEX_DATA_IDX 1
+
+static struct usb_string obex_string_defs[] = {
+ [OBEX_CTRL_IDX].s = "CDC Object Exchange (OBEX)",
+ [OBEX_DATA_IDX].s = "CDC OBEX Data",
+ { }, /* end of list */
+};
+
+static struct usb_gadget_strings obex_string_table = {
+ .language = 0x0409, /* en-US */
+ .strings = obex_string_defs,
+};
+
+static struct usb_gadget_strings *obex_strings[] = {
+ &obex_string_table,
+ NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_interface_descriptor obex_control_intf __initdata = {
+ .bLength = sizeof(obex_control_intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX,
+};
+
+static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
+ .bLength = sizeof(obex_data_nop_intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 1,
+
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+};
+
+static struct usb_interface_descriptor obex_data_intf __initdata = {
+ .bLength = sizeof(obex_data_intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 2,
+
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+};
+
+static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = {
+ .bLength = sizeof(obex_cdc_header_desc),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_HEADER_TYPE,
+ .bcdCDC = __constant_cpu_to_le16(0x0120),
+};
+
+static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
+ .bLength = sizeof(obex_cdc_union_desc),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_UNION_TYPE,
+ .bMasterInterface0 = 1,
+ .bSlaveInterface0 = 2,
+};
+
+static struct usb_cdc_obex_desc obex_desc __initdata = {
+ .bLength = sizeof(obex_desc),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_OBEX_TYPE,
+ .bcdVersion = __constant_cpu_to_le16(0x0100),
+};
+
+/* High-Speed Support */
+
+static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *hs_function[] __initdata = {
+ (struct usb_descriptor_header *) &obex_control_intf,
+ (struct usb_descriptor_header *) &obex_cdc_header_desc,
+ (struct usb_descriptor_header *) &obex_desc,
+ (struct usb_descriptor_header *) &obex_cdc_union_desc,
+
+ (struct usb_descriptor_header *) &obex_data_nop_intf,
+ (struct usb_descriptor_header *) &obex_data_intf,
+ (struct usb_descriptor_header *) &obex_hs_ep_in_desc,
+ (struct usb_descriptor_header *) &obex_hs_ep_out_desc,
+ NULL,
+};
+
+/* Full-Speed Support */
+
+static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *fs_function[] __initdata = {
+ (struct usb_descriptor_header *) &obex_control_intf,
+ (struct usb_descriptor_header *) &obex_cdc_header_desc,
+ (struct usb_descriptor_header *) &obex_desc,
+ (struct usb_descriptor_header *) &obex_cdc_union_desc,
+
+ (struct usb_descriptor_header *) &obex_data_nop_intf,
+ (struct usb_descriptor_header *) &obex_data_intf,
+ (struct usb_descriptor_header *) &obex_fs_ep_in_desc,
+ (struct usb_descriptor_header *) &obex_fs_ep_out_desc,
+ NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct f_obex *obex = func_to_obex(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+
+ if (intf == obex->ctrl_id) {
+ if (alt != 0)
+ goto fail;
+ /* NOP */
+ DBG(cdev, "reset obex ttyGS%d control\n", obex->port_num);
+
+ } else if (intf == obex->data_id) {
+ if (alt > 1)
+ goto fail;
+
+ if (obex->port.in->driver_data) {
+ DBG(cdev, "reset obex ttyGS%d\n", obex->port_num);
+ gserial_disconnect(&obex->port);
+ }
+
+ if (!obex->port.in_desc) {
+ DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
+ obex->port.in_desc = ep_choose(cdev->gadget,
+ obex->hs.obex_in, obex->fs.obex_in);
+ obex->port.out_desc = ep_choose(cdev->gadget,
+ obex->hs.obex_out, obex->fs.obex_out);
+ }
+
+ if (alt == 1) {
+ DBG(cdev, "activate obex ttyGS%d\n", obex->port_num);
+ gserial_connect(&obex->port, obex->port_num);
+ }
+
+ } else
+ goto fail;
+
+ return 0;
+
+fail:
+ return -EINVAL;
+}
+
+static int obex_get_alt(struct usb_function *f, unsigned intf)
+{
+ struct f_obex *obex = func_to_obex(f);
+
+ if (intf == obex->ctrl_id)
+ return 0;
+
+ return obex->port.in->driver_data ? 1 : 0;
+}
+
+static void obex_disable(struct usb_function *f)
+{
+ struct f_obex *obex = func_to_obex(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+
+ DBG(cdev, "obex ttyGS%d disable\n", obex->port_num);
+ gserial_disconnect(&obex->port);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void obex_connect(struct gserial *g)
+{
+ struct f_obex *obex = port_to_obex(g);
+ struct usb_composite_dev *cdev = g->func.config->cdev;
+ int status;
+
+ if (!obex->can_activate)
+ return;
+
+ status = usb_function_activate(&g->func);
+ if (status)
+ DBG(cdev, "obex ttyGS%d function activate --> %d\n",
+ obex->port_num, status);
+}
+
+static void obex_disconnect(struct gserial *g)
+{
+ struct f_obex *obex = port_to_obex(g);
+ struct usb_composite_dev *cdev = g->func.config->cdev;
+ int status;
+
+ if (!obex->can_activate)
+ return;
+
+ status = usb_function_deactivate(&g->func);
+ if (status)
+ DBG(cdev, "obex ttyGS%d function deactivate --> %d\n",
+ obex->port_num, status);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __init
+obex_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = c->cdev;
+ struct f_obex *obex = func_to_obex(f);
+ int status;
+ struct usb_ep *ep;
+
+ /* allocate instance-specific interface IDs, and patch descriptors */
+
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ obex->ctrl_id = status;
+
+ obex_control_intf.bInterfaceNumber = status;
+ obex_cdc_union_desc.bMasterInterface0 = status;
+
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ obex->data_id = status;
+
+ obex_data_nop_intf.bInterfaceNumber = status;
+ obex_data_intf.bInterfaceNumber = status;
+ obex_cdc_union_desc.bSlaveInterface0 = status;
+
+ /* allocate instance-specific endpoints */
+
+ ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_in_desc);
+ if (!ep)
+ goto fail;
+ obex->port.in = ep;
+ ep->driver_data = cdev; /* claim */
+
+ ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_out_desc);
+ if (!ep)
+ goto fail;
+ obex->port.out = ep;
+ ep->driver_data = cdev; /* claim */
+
+ /* copy descriptors, and track endpoint copies */
+ f->descriptors = usb_copy_descriptors(fs_function);
+
+ obex->fs.obex_in = usb_find_endpoint(fs_function,
+ f->descriptors, &obex_fs_ep_in_desc);
+ obex->fs.obex_out = usb_find_endpoint(fs_function,
+ f->descriptors, &obex_fs_ep_out_desc);
+
+ /* support all relevant hardware speeds... we expect that when
+ * hardware is dual speed, all bulk-capable endpoints work at
+ * both speeds
+ */
+ if (gadget_is_dualspeed(c->cdev->gadget)) {
+
+ obex_hs_ep_in_desc.bEndpointAddress =
+ obex_fs_ep_in_desc.bEndpointAddress;
+ obex_hs_ep_out_desc.bEndpointAddress =
+ obex_fs_ep_out_desc.bEndpointAddress;
+
+ /* copy descriptors, and track endpoint copies */
+ f->hs_descriptors = usb_copy_descriptors(hs_function);
+
+ obex->hs.obex_in = usb_find_endpoint(hs_function,
+ f->descriptors, &obex_hs_ep_in_desc);
+ obex->hs.obex_out = usb_find_endpoint(hs_function,
+ f->descriptors, &obex_hs_ep_out_desc);
+ }
+
+ /* Avoid letting this gadget enumerate until the userspace
+ * OBEX server is active.
+ */
+ status = usb_function_deactivate(f);
+ if (status < 0)
+ WARNING(cdev, "obex ttyGS%d: can't prevent enumeration, %d\n",
+ obex->port_num, status);
+ else
+ obex->can_activate = true;
+
+
+ DBG(cdev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n",
+ obex->port_num,
+ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+ obex->port.in->name, obex->port.out->name);
+
+ return 0;
+
+fail:
+ /* we might as well release our claims on endpoints */
+ if (obex->port.out)
+ obex->port.out->driver_data = NULL;
+ if (obex->port.in)
+ obex->port.in->driver_data = NULL;
+
+ ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
+
+ return status;
+}
+
+static void
+obex_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ if (gadget_is_dualspeed(c->cdev->gadget))
+ usb_free_descriptors(f->hs_descriptors);
+ usb_free_descriptors(f->descriptors);
+ kfree(func_to_obex(f));
+}
+
+/* Some controllers can't support CDC OBEX ... */
+static inline bool can_support_obex(struct usb_configuration *c)
+{
+ /* Since the first interface is a NOP, we can ignore the
+ * issue of multi-interface support on most controllers.
+ *
+ * Altsettings are mandatory, however...
+ */
+ if (!gadget_supports_altsettings(c->cdev->gadget))
+ return false;
+
+ /* everything else is *probably* fine ... */
+ return true;
+}
+
+/**
+ * obex_bind_config - add a CDC OBEX function to a configuration
+ * @c: the configuration to support the CDC OBEX instance
+ * @port_num: /dev/ttyGS* port this interface will use
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gserial_setup() with enough ports to
+ * handle all the ones it binds. Caller is also responsible
+ * for calling @gserial_cleanup() before module unload.
+ */
+int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
+{
+ struct f_obex *obex;
+ int status;
+
+ if (!can_support_obex(c))
+ return -EINVAL;
+
+ /* maybe allocate device-global string IDs, and patch descriptors */
+ if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ obex_string_defs[OBEX_CTRL_IDX].id = status;
+
+ obex_control_intf.iInterface = status;
+
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ obex_string_defs[OBEX_DATA_IDX].id = status;
+
+ obex_data_nop_intf.iInterface =
+ obex_data_intf.iInterface = status;
+ }
+
+ /* allocate and initialize one new instance */
+ obex = kzalloc(sizeof *obex, GFP_KERNEL);
+ if (!obex)
+ return -ENOMEM;
+
+ obex->port_num = port_num;
+
+ obex->port.connect = obex_connect;
+ obex->port.disconnect = obex_disconnect;
+
+ obex->port.func.name = "obex";
+ obex->port.func.strings = obex_strings;
+ /* descriptors are per-instance copies */
+ obex->port.func.bind = obex_bind;
+ obex->port.func.unbind = obex_unbind;
+ obex->port.func.set_alt = obex_set_alt;
+ obex->port.func.get_alt = obex_get_alt;
+ obex->port.func.disable = obex_disable;
+
+ status = usb_add_function(c, &obex->port.func);
+ if (status)
+ kfree(obex);
+
+ return status;
+}
+
+MODULE_AUTHOR("Felipe Balbi");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index f18c3a14d72..dc84d26d283 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -552,7 +552,6 @@ static struct usb_configuration sourcesink_driver = {
.setup = sourcesink_setup,
.bConfigurationValue = 3,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1, /* 2 mA, minimal */
/* .iConfiguration = DYNAMIC */
};
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 0c632d22a63..c4e62a6297d 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -851,7 +851,7 @@ config_desc = {
.bConfigurationValue = CONFIG_VALUE,
.iConfiguration = STRING_CONFIG,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1, // self-powered
+ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
};
static struct usb_otg_descriptor
@@ -2676,11 +2676,24 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
/* Verify the length of the command itself */
if (cmnd_size != fsg->cmnd_size) {
- /* Special case workaround: MS-Windows issues REQUEST SENSE
- * with cbw->Length == 12 (it should be 6). */
- if (fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12)
+ /* Special case workaround: There are plenty of buggy SCSI
+ * implementations. Many have issues with cbw->Length
+ * field passing a wrong command size. For those cases we
+ * always try to work around the problem by using the length
+ * sent by the host side provided it is at least as large
+ * as the correct command length.
+ * Examples of such cases would be MS-Windows, which issues
+ * REQUEST SENSE with cbw->Length == 12 where it should
+ * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
+ * REQUEST SENSE with cbw->Length == 10 where it should
+ * be 6 as well.
+ */
+ if (cmnd_size <= fsg->cmnd_size) {
+ DBG(fsg, "%s is buggy! Expected length %d "
+ "but we got %d\n", name,
+ cmnd_size, fsg->cmnd_size);
cmnd_size = fsg->cmnd_size;
- else {
+ } else {
fsg->phase_error = 1;
return -EINVAL;
}
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
new file mode 100644
index 00000000000..1fe8b44787b
--- /dev/null
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -0,0 +1,2760 @@
+/*
+ * driver/usb/gadget/fsl_qe_udc.c
+ *
+ * Copyright (c) 2006-2008 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Xie Xiaobo <X.Xie@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ * Based on bareboard code from Shlomi Gridish.
+ *
+ * Description:
+ * Freescle QE/CPM USB Pheripheral Controller Driver
+ * The controller can be found on MPC8360, MPC8272, and etc.
+ * MPC8360 Rev 1.1 may need QE mircocode update
+ *
+ * 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.
+ */
+
+#undef USB_TRACE
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/moduleparam.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <asm/qe.h>
+#include <asm/cpm.h>
+#include <asm/dma.h>
+#include <asm/reg.h>
+#include "fsl_qe_udc.h"
+
+#define DRIVER_DESC "Freescale QE/CPM USB Device Controller driver"
+#define DRIVER_AUTHOR "Xie XiaoBo"
+#define DRIVER_VERSION "1.0"
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+static const char driver_name[] = "fsl_qe_udc";
+static const char driver_desc[] = DRIVER_DESC;
+
+/*ep name is important in gadget, it should obey the convention of ep_match()*/
+static const char *const ep_name[] = {
+ "ep0-control", /* everyone has ep0 */
+ /* 3 configurable endpoints */
+ "ep1",
+ "ep2",
+ "ep3",
+};
+
+static struct usb_endpoint_descriptor qe_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
+};
+
+/* it is initialized in probe() */
+static struct qe_udc *udc_controller;
+
+/********************************************************************
+ * Internal Used Function Start
+********************************************************************/
+/*-----------------------------------------------------------------
+ * done() - retire a request; caller blocked irqs
+ *--------------------------------------------------------------*/
+static void done(struct qe_ep *ep, struct qe_req *req, int status)
+{
+ struct qe_udc *udc = ep->udc;
+ unsigned char stopped = ep->stopped;
+
+ /* the req->queue pointer is used by ep_queue() func, in which
+ * the request will be added into a udc_ep->queue 'd tail
+ * so here the req will be dropped from the ep->queue
+ */
+ list_del_init(&req->queue);
+
+ /* req.status should be set as -EINPROGRESS in ep_queue() */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (req->mapped) {
+ dma_unmap_single(udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ } else
+ dma_sync_single_for_cpu(udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ if (status && (status != -ESHUTDOWN))
+ dev_vdbg(udc->dev, "complete %s req %p stat %d len %u/%u\n",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ /* don't modify queue heads during completion callback */
+ ep->stopped = 1;
+ spin_unlock(&udc->lock);
+
+ /* this complete() should a func implemented by gadget layer,
+ * eg fsg->bulk_in_complete() */
+ if (req->req.complete)
+ req->req.complete(&ep->ep, &req->req);
+
+ spin_lock(&udc->lock);
+
+ ep->stopped = stopped;
+}
+
+/*-----------------------------------------------------------------
+ * nuke(): delete all requests related to this ep
+ *--------------------------------------------------------------*/
+static void nuke(struct qe_ep *ep, int status)
+{
+ /* Whether this eq has request linked */
+ while (!list_empty(&ep->queue)) {
+ struct qe_req *req = NULL;
+ req = list_entry(ep->queue.next, struct qe_req, queue);
+
+ done(ep, req, status);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * USB and Endpoint manipulate process, include parameter and register *
+ *---------------------------------------------------------------------------*/
+/* @value: 1--set stall 0--clean stall */
+static int qe_eprx_stall_change(struct qe_ep *ep, int value)
+{
+ u16 tem_usep;
+ u8 epnum = ep->epnum;
+ struct qe_udc *udc = ep->udc;
+
+ tem_usep = in_be16(&udc->usb_regs->usb_usep[epnum]);
+ tem_usep = tem_usep & ~USB_RHS_MASK;
+ if (value == 1)
+ tem_usep |= USB_RHS_STALL;
+ else if (ep->dir == USB_DIR_IN)
+ tem_usep |= USB_RHS_IGNORE_OUT;
+
+ out_be16(&udc->usb_regs->usb_usep[epnum], tem_usep);
+ return 0;
+}
+
+static int qe_eptx_stall_change(struct qe_ep *ep, int value)
+{
+ u16 tem_usep;
+ u8 epnum = ep->epnum;
+ struct qe_udc *udc = ep->udc;
+
+ tem_usep = in_be16(&udc->usb_regs->usb_usep[epnum]);
+ tem_usep = tem_usep & ~USB_THS_MASK;
+ if (value == 1)
+ tem_usep |= USB_THS_STALL;
+ else if (ep->dir == USB_DIR_OUT)
+ tem_usep |= USB_THS_IGNORE_IN;
+
+ out_be16(&udc->usb_regs->usb_usep[epnum], tem_usep);
+
+ return 0;
+}
+
+static int qe_ep0_stall(struct qe_udc *udc)
+{
+ qe_eptx_stall_change(&udc->eps[0], 1);
+ qe_eprx_stall_change(&udc->eps[0], 1);
+ udc_controller->ep0_state = WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = 0;
+ return 0;
+}
+
+static int qe_eprx_nack(struct qe_ep *ep)
+{
+ u8 epnum = ep->epnum;
+ struct qe_udc *udc = ep->udc;
+
+ if (ep->state == EP_STATE_IDLE) {
+ /* Set the ep's nack */
+ clrsetbits_be16(&udc->usb_regs->usb_usep[epnum],
+ USB_RHS_MASK, USB_RHS_NACK);
+
+ /* Mask Rx and Busy interrupts */
+ clrbits16(&udc->usb_regs->usb_usbmr,
+ (USB_E_RXB_MASK | USB_E_BSY_MASK));
+
+ ep->state = EP_STATE_NACK;
+ }
+ return 0;
+}
+
+static int qe_eprx_normal(struct qe_ep *ep)
+{
+ struct qe_udc *udc = ep->udc;
+
+ if (ep->state == EP_STATE_NACK) {
+ clrsetbits_be16(&udc->usb_regs->usb_usep[ep->epnum],
+ USB_RTHS_MASK, USB_THS_IGNORE_IN);
+
+ /* Unmask RX interrupts */
+ out_be16(&udc->usb_regs->usb_usber,
+ USB_E_BSY_MASK | USB_E_RXB_MASK);
+ setbits16(&udc->usb_regs->usb_usbmr,
+ (USB_E_RXB_MASK | USB_E_BSY_MASK));
+
+ ep->state = EP_STATE_IDLE;
+ ep->has_data = 0;
+ }
+
+ return 0;
+}
+
+static int qe_ep_cmd_stoptx(struct qe_ep *ep)
+{
+ if (ep->udc->soc_type == PORT_CPM)
+ cpm_command(CPM_USB_STOP_TX | (ep->epnum << CPM_USB_EP_SHIFT),
+ CPM_USB_STOP_TX_OPCODE);
+ else
+ qe_issue_cmd(QE_USB_STOP_TX, QE_CR_SUBBLOCK_USB,
+ ep->epnum, 0);
+
+ return 0;
+}
+
+static int qe_ep_cmd_restarttx(struct qe_ep *ep)
+{
+ if (ep->udc->soc_type == PORT_CPM)
+ cpm_command(CPM_USB_RESTART_TX | (ep->epnum <<
+ CPM_USB_EP_SHIFT), CPM_USB_RESTART_TX_OPCODE);
+ else
+ qe_issue_cmd(QE_USB_RESTART_TX, QE_CR_SUBBLOCK_USB,
+ ep->epnum, 0);
+
+ return 0;
+}
+
+static int qe_ep_flushtxfifo(struct qe_ep *ep)
+{
+ struct qe_udc *udc = ep->udc;
+ int i;
+
+ i = (int)ep->epnum;
+
+ qe_ep_cmd_stoptx(ep);
+ out_8(&udc->usb_regs->usb_uscom,
+ USB_CMD_FLUSH_FIFO | (USB_CMD_EP_MASK & (ep->epnum)));
+ out_be16(&udc->ep_param[i]->tbptr, in_be16(&udc->ep_param[i]->tbase));
+ out_be32(&udc->ep_param[i]->tstate, 0);
+ out_be16(&udc->ep_param[i]->tbcnt, 0);
+
+ ep->c_txbd = ep->txbase;
+ ep->n_txbd = ep->txbase;
+ qe_ep_cmd_restarttx(ep);
+ return 0;
+}
+
+static int qe_ep_filltxfifo(struct qe_ep *ep)
+{
+ struct qe_udc *udc = ep->udc;
+
+ out_8(&udc->usb_regs->usb_uscom,
+ USB_CMD_STR_FIFO | (USB_CMD_EP_MASK & (ep->epnum)));
+ return 0;
+}
+
+static int qe_epbds_reset(struct qe_udc *udc, int pipe_num)
+{
+ struct qe_ep *ep;
+ u32 bdring_len;
+ struct qe_bd __iomem *bd;
+ int i;
+
+ ep = &udc->eps[pipe_num];
+
+ if (ep->dir == USB_DIR_OUT)
+ bdring_len = USB_BDRING_LEN_RX;
+ else
+ bdring_len = USB_BDRING_LEN;
+
+ bd = ep->rxbase;
+ for (i = 0; i < (bdring_len - 1); i++) {
+ out_be32((u32 __iomem *)bd, R_E | R_I);
+ bd++;
+ }
+ out_be32((u32 __iomem *)bd, R_E | R_I | R_W);
+
+ bd = ep->txbase;
+ for (i = 0; i < USB_BDRING_LEN_TX - 1; i++) {
+ out_be32(&bd->buf, 0);
+ out_be32((u32 __iomem *)bd, 0);
+ bd++;
+ }
+ out_be32((u32 __iomem *)bd, T_W);
+
+ return 0;
+}
+
+static int qe_ep_reset(struct qe_udc *udc, int pipe_num)
+{
+ struct qe_ep *ep;
+ u16 tmpusep;
+
+ ep = &udc->eps[pipe_num];
+ tmpusep = in_be16(&udc->usb_regs->usb_usep[pipe_num]);
+ tmpusep &= ~USB_RTHS_MASK;
+
+ switch (ep->dir) {
+ case USB_DIR_BOTH:
+ qe_ep_flushtxfifo(ep);
+ break;
+ case USB_DIR_OUT:
+ tmpusep |= USB_THS_IGNORE_IN;
+ break;
+ case USB_DIR_IN:
+ qe_ep_flushtxfifo(ep);
+ tmpusep |= USB_RHS_IGNORE_OUT;
+ break;
+ default:
+ break;
+ }
+ out_be16(&udc->usb_regs->usb_usep[pipe_num], tmpusep);
+
+ qe_epbds_reset(udc, pipe_num);
+
+ return 0;
+}
+
+static int qe_ep_toggledata01(struct qe_ep *ep)
+{
+ ep->data01 ^= 0x1;
+ return 0;
+}
+
+static int qe_ep_bd_init(struct qe_udc *udc, unsigned char pipe_num)
+{
+ struct qe_ep *ep = &udc->eps[pipe_num];
+ unsigned long tmp_addr = 0;
+ struct usb_ep_para __iomem *epparam;
+ int i;
+ struct qe_bd __iomem *bd;
+ int bdring_len;
+
+ if (ep->dir == USB_DIR_OUT)
+ bdring_len = USB_BDRING_LEN_RX;
+ else
+ bdring_len = USB_BDRING_LEN;
+
+ epparam = udc->ep_param[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);
+ out_be16(&epparam->rbase, (u16)tmp_addr);
+ out_be16(&epparam->tbase, (u16)(tmp_addr +
+ (sizeof(struct qe_bd) * bdring_len)));
+
+ out_be16(&epparam->rbptr, in_be16(&epparam->rbase));
+ out_be16(&epparam->tbptr, in_be16(&epparam->tbase));
+
+ ep->rxbase = cpm_muram_addr(tmp_addr);
+ ep->txbase = cpm_muram_addr(tmp_addr + (sizeof(struct qe_bd)
+ * bdring_len));
+ ep->n_rxbd = ep->rxbase;
+ ep->e_rxbd = ep->rxbase;
+ ep->n_txbd = ep->txbase;
+ ep->c_txbd = ep->txbase;
+ ep->data01 = 0; /* data0 */
+
+ /* Init TX and RX bds */
+ bd = ep->rxbase;
+ for (i = 0; i < bdring_len - 1; i++) {
+ out_be32(&bd->buf, 0);
+ out_be32((u32 __iomem *)bd, 0);
+ bd++;
+ }
+ out_be32(&bd->buf, 0);
+ out_be32((u32 __iomem *)bd, R_W);
+
+ bd = ep->txbase;
+ for (i = 0; i < USB_BDRING_LEN_TX - 1; i++) {
+ out_be32(&bd->buf, 0);
+ out_be32((u32 __iomem *)bd, 0);
+ bd++;
+ }
+ out_be32(&bd->buf, 0);
+ out_be32((u32 __iomem *)bd, T_W);
+
+ return 0;
+}
+
+static int qe_ep_rxbd_update(struct qe_ep *ep)
+{
+ unsigned int size;
+ int i;
+ unsigned int tmp;
+ struct qe_bd __iomem *bd;
+ unsigned int bdring_len;
+
+ if (ep->rxbase == NULL)
+ return -EINVAL;
+
+ bd = ep->rxbase;
+
+ ep->rxframe = kmalloc(sizeof(*ep->rxframe), GFP_ATOMIC);
+ if (ep->rxframe == NULL) {
+ dev_err(ep->udc->dev, "malloc rxframe failed\n");
+ return -ENOMEM;
+ }
+
+ qe_frame_init(ep->rxframe);
+
+ if (ep->dir == USB_DIR_OUT)
+ bdring_len = USB_BDRING_LEN_RX;
+ else
+ bdring_len = USB_BDRING_LEN;
+
+ size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (bdring_len + 1);
+ ep->rxbuffer = kzalloc(size, GFP_ATOMIC);
+ if (ep->rxbuffer == NULL) {
+ dev_err(ep->udc->dev, "malloc rxbuffer failed,size=%d\n",
+ size);
+ kfree(ep->rxframe);
+ return -ENOMEM;
+ }
+
+ ep->rxbuf_d = virt_to_phys((void *)ep->rxbuffer);
+ if (ep->rxbuf_d == DMA_ADDR_INVALID) {
+ ep->rxbuf_d = dma_map_single(udc_controller->gadget.dev.parent,
+ ep->rxbuffer,
+ size,
+ DMA_FROM_DEVICE);
+ ep->rxbufmap = 1;
+ } else {
+ dma_sync_single_for_device(udc_controller->gadget.dev.parent,
+ ep->rxbuf_d, size,
+ DMA_FROM_DEVICE);
+ ep->rxbufmap = 0;
+ }
+
+ size = ep->ep.maxpacket + USB_CRC_SIZE + 2;
+ tmp = ep->rxbuf_d;
+ tmp = (u32)(((tmp >> 2) << 2) + 4);
+
+ for (i = 0; i < bdring_len - 1; i++) {
+ out_be32(&bd->buf, tmp);
+ out_be32((u32 __iomem *)bd, (R_E | R_I));
+ tmp = tmp + size;
+ bd++;
+ }
+ out_be32(&bd->buf, tmp);
+ out_be32((u32 __iomem *)bd, (R_E | R_I | R_W));
+
+ return 0;
+}
+
+static int qe_ep_register_init(struct qe_udc *udc, unsigned char pipe_num)
+{
+ struct qe_ep *ep = &udc->eps[pipe_num];
+ struct usb_ep_para __iomem *epparam;
+ u16 usep, logepnum;
+ u16 tmp;
+ u8 rtfcr = 0;
+
+ epparam = udc->ep_param[pipe_num];
+
+ usep = 0;
+ logepnum = (ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ usep |= (logepnum << USB_EPNUM_SHIFT);
+
+ switch (ep->desc->bmAttributes & 0x03) {
+ case USB_ENDPOINT_XFER_BULK:
+ usep |= USB_TRANS_BULK;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ usep |= USB_TRANS_ISO;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ usep |= USB_TRANS_INT;
+ break;
+ default:
+ usep |= USB_TRANS_CTR;
+ break;
+ }
+
+ switch (ep->dir) {
+ case USB_DIR_OUT:
+ usep |= USB_THS_IGNORE_IN;
+ break;
+ case USB_DIR_IN:
+ usep |= USB_RHS_IGNORE_OUT;
+ break;
+ default:
+ break;
+ }
+ out_be16(&udc->usb_regs->usb_usep[pipe_num], usep);
+
+ rtfcr = 0x30;
+ out_8(&epparam->rbmr, rtfcr);
+ out_8(&epparam->tbmr, rtfcr);
+
+ tmp = (u16)(ep->ep.maxpacket + USB_CRC_SIZE);
+ /* MRBLR must be divisble by 4 */
+ tmp = (u16)(((tmp >> 2) << 2) + 4);
+ out_be16(&epparam->mrblr, tmp);
+
+ return 0;
+}
+
+static int qe_ep_init(struct qe_udc *udc,
+ unsigned char pipe_num,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct qe_ep *ep = &udc->eps[pipe_num];
+ unsigned long flags;
+ int reval = 0;
+ u16 max = 0;
+
+ max = le16_to_cpu(desc->wMaxPacketSize);
+
+ /* check the max package size validate for this endpoint */
+ /* Refer to USB2.0 spec table 9-13,
+ */
+ if (pipe_num != 0) {
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (strstr(ep->ep.name, "-iso")
+ || strstr(ep->ep.name, "-int"))
+ goto en_done;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ if ((max == 128) || (max == 256) || (max == 512))
+ break;
+ default:
+ switch (max) {
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ break;
+ default:
+ case USB_SPEED_LOW:
+ goto en_done;
+ }
+ }
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
+ goto en_done;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ if (max <= 1024)
+ break;
+ case USB_SPEED_FULL:
+ if (max <= 64)
+ break;
+ default:
+ if (max <= 8)
+ break;
+ goto en_done;
+ }
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (strstr(ep->ep.name, "-bulk")
+ || strstr(ep->ep.name, "-int"))
+ goto en_done;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ if (max <= 1024)
+ break;
+ case USB_SPEED_FULL:
+ if (max <= 1023)
+ break;
+ default:
+ goto en_done;
+ }
+ break;
+ case USB_ENDPOINT_XFER_CONTROL:
+ if (strstr(ep->ep.name, "-iso")
+ || strstr(ep->ep.name, "-int"))
+ goto en_done;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
+ switch (max) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ break;
+ default:
+ goto en_done;
+ }
+ case USB_SPEED_LOW:
+ switch (max) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ goto en_done;
+ }
+ default:
+ goto en_done;
+ }
+ break;
+
+ default:
+ goto en_done;
+ }
+ } /* if ep0*/
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* initialize ep structure */
+ ep->ep.maxpacket = max;
+ ep->tm = (u8)(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ ep->desc = desc;
+ ep->stopped = 0;
+ ep->init = 1;
+
+ if (pipe_num == 0) {
+ ep->dir = USB_DIR_BOTH;
+ udc->ep0_dir = USB_DIR_OUT;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ } else {
+ switch (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+ case USB_DIR_OUT:
+ ep->dir = USB_DIR_OUT;
+ break;
+ case USB_DIR_IN:
+ ep->dir = USB_DIR_IN;
+ default:
+ break;
+ }
+ }
+
+ /* hardware special operation */
+ qe_ep_bd_init(udc, pipe_num);
+ if ((ep->tm == USBP_TM_CTL) || (ep->dir == USB_DIR_OUT)) {
+ reval = qe_ep_rxbd_update(ep);
+ if (reval)
+ goto en_done1;
+ }
+
+ if ((ep->tm == USBP_TM_CTL) || (ep->dir == USB_DIR_IN)) {
+ ep->txframe = kmalloc(sizeof(*ep->txframe), GFP_ATOMIC);
+ if (ep->txframe == NULL) {
+ dev_err(udc->dev, "malloc txframe failed\n");
+ goto en_done2;
+ }
+ qe_frame_init(ep->txframe);
+ }
+
+ qe_ep_register_init(udc, pipe_num);
+
+ /* Now HW will be NAKing transfers to that EP,
+ * until a buffer is queued to it. */
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+en_done2:
+ kfree(ep->rxbuffer);
+ kfree(ep->rxframe);
+en_done1:
+ spin_unlock_irqrestore(&udc->lock, flags);
+en_done:
+ dev_dbg(udc->dev, "failed to initialize %s\n", ep->ep.name);
+ return -ENODEV;
+}
+
+static inline void qe_usb_enable(void)
+{
+ setbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN);
+}
+
+static inline void qe_usb_disable(void)
+{
+ clrbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN);
+}
+
+/*----------------------------------------------------------------------------*
+ * USB and EP basic manipulate function end *
+ *----------------------------------------------------------------------------*/
+
+
+/******************************************************************************
+ UDC transmit and receive process
+ ******************************************************************************/
+static void recycle_one_rxbd(struct qe_ep *ep)
+{
+ u32 bdstatus;
+
+ bdstatus = in_be32((u32 __iomem *)ep->e_rxbd);
+ bdstatus = R_I | R_E | (bdstatus & R_W);
+ out_be32((u32 __iomem *)ep->e_rxbd, bdstatus);
+
+ if (bdstatus & R_W)
+ ep->e_rxbd = ep->rxbase;
+ else
+ ep->e_rxbd++;
+}
+
+static void recycle_rxbds(struct qe_ep *ep, unsigned char stopatnext)
+{
+ u32 bdstatus;
+ struct qe_bd __iomem *bd, *nextbd;
+ unsigned char stop = 0;
+
+ nextbd = ep->n_rxbd;
+ bd = ep->e_rxbd;
+ bdstatus = in_be32((u32 __iomem *)bd);
+
+ while (!(bdstatus & R_E) && !(bdstatus & BD_LENGTH_MASK) && !stop) {
+ bdstatus = R_E | R_I | (bdstatus & R_W);
+ out_be32((u32 __iomem *)bd, bdstatus);
+
+ if (bdstatus & R_W)
+ bd = ep->rxbase;
+ else
+ bd++;
+
+ bdstatus = in_be32((u32 __iomem *)bd);
+ if (stopatnext && (bd == nextbd))
+ stop = 1;
+ }
+
+ ep->e_rxbd = bd;
+}
+
+static void ep_recycle_rxbds(struct qe_ep *ep)
+{
+ struct qe_bd __iomem *bd = ep->n_rxbd;
+ u32 bdstatus;
+ u8 epnum = ep->epnum;
+ struct qe_udc *udc = ep->udc;
+
+ bdstatus = in_be32((u32 __iomem *)bd);
+ if (!(bdstatus & R_E) && !(bdstatus & BD_LENGTH_MASK)) {
+ bd = ep->rxbase +
+ ((in_be16(&udc->ep_param[epnum]->rbptr) -
+ in_be16(&udc->ep_param[epnum]->rbase))
+ >> 3);
+ bdstatus = in_be32((u32 __iomem *)bd);
+
+ if (bdstatus & R_W)
+ bd = ep->rxbase;
+ else
+ bd++;
+
+ ep->e_rxbd = bd;
+ recycle_rxbds(ep, 0);
+ ep->e_rxbd = ep->n_rxbd;
+ } else
+ recycle_rxbds(ep, 1);
+
+ if (in_be16(&udc->usb_regs->usb_usber) & USB_E_BSY_MASK)
+ out_be16(&udc->usb_regs->usb_usber, USB_E_BSY_MASK);
+
+ if (ep->has_data <= 0 && (!list_empty(&ep->queue)))
+ qe_eprx_normal(ep);
+
+ ep->localnack = 0;
+}
+
+static void setup_received_handle(struct qe_udc *udc,
+ struct usb_ctrlrequest *setup);
+static int qe_ep_rxframe_handle(struct qe_ep *ep);
+static void ep0_req_complete(struct qe_udc *udc, struct qe_req *req);
+/* when BD PID is setup, handle the packet */
+static int ep0_setup_handle(struct qe_udc *udc)
+{
+ struct qe_ep *ep = &udc->eps[0];
+ struct qe_frame *pframe;
+ unsigned int fsize;
+ u8 *cp;
+
+ pframe = ep->rxframe;
+ if ((frame_get_info(pframe) & PID_SETUP)
+ && (udc->ep0_state == WAIT_FOR_SETUP)) {
+ fsize = frame_get_length(pframe);
+ if (unlikely(fsize != 8))
+ return -EINVAL;
+ cp = (u8 *)&udc->local_setup_buff;
+ memcpy(cp, pframe->data, fsize);
+ ep->data01 = 1;
+
+ /* handle the usb command base on the usb_ctrlrequest */
+ setup_received_handle(udc, &udc->local_setup_buff);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int qe_ep0_rx(struct qe_udc *udc)
+{
+ struct qe_ep *ep = &udc->eps[0];
+ struct qe_frame *pframe;
+ struct qe_bd __iomem *bd;
+ u32 bdstatus, length;
+ u32 vaddr;
+
+ pframe = ep->rxframe;
+
+ if (ep->dir == USB_DIR_IN) {
+ dev_err(udc->dev, "ep0 not a control endpoint\n");
+ return -EINVAL;
+ }
+
+ bd = ep->n_rxbd;
+ bdstatus = in_be32((u32 __iomem *)bd);
+ length = bdstatus & BD_LENGTH_MASK;
+
+ while (!(bdstatus & R_E) && length) {
+ if ((bdstatus & R_F) && (bdstatus & R_L)
+ && !(bdstatus & R_ERROR)) {
+ if (length == USB_CRC_SIZE) {
+ udc->ep0_state = WAIT_FOR_SETUP;
+ dev_vdbg(udc->dev,
+ "receive a ZLP in status phase\n");
+ } else {
+ qe_frame_clean(pframe);
+ vaddr = (u32)phys_to_virt(in_be32(&bd->buf));
+ frame_set_data(pframe, (u8 *)vaddr);
+ frame_set_length(pframe,
+ (length - USB_CRC_SIZE));
+ frame_set_status(pframe, FRAME_OK);
+ switch (bdstatus & R_PID) {
+ case R_PID_SETUP:
+ frame_set_info(pframe, PID_SETUP);
+ break;
+ case R_PID_DATA1:
+ frame_set_info(pframe, PID_DATA1);
+ break;
+ default:
+ frame_set_info(pframe, PID_DATA0);
+ break;
+ }
+
+ if ((bdstatus & R_PID) == R_PID_SETUP)
+ ep0_setup_handle(udc);
+ else
+ qe_ep_rxframe_handle(ep);
+ }
+ } else {
+ dev_err(udc->dev, "The receive frame with error!\n");
+ }
+
+ /* note: don't clear the rxbd's buffer address */
+ recycle_one_rxbd(ep);
+
+ /* Get next BD */
+ if (bdstatus & R_W)
+ bd = ep->rxbase;
+ else
+ bd++;
+
+ bdstatus = in_be32((u32 __iomem *)bd);
+ length = bdstatus & BD_LENGTH_MASK;
+
+ }
+
+ ep->n_rxbd = bd;
+
+ return 0;
+}
+
+static int qe_ep_rxframe_handle(struct qe_ep *ep)
+{
+ struct qe_frame *pframe;
+ u8 framepid = 0;
+ unsigned int fsize;
+ u8 *cp;
+ struct qe_req *req;
+
+ pframe = ep->rxframe;
+
+ if (frame_get_info(pframe) & PID_DATA1)
+ framepid = 0x1;
+
+ if (framepid != ep->data01) {
+ dev_err(ep->udc->dev, "the data01 error!\n");
+ return -EIO;
+ }
+
+ fsize = frame_get_length(pframe);
+ if (list_empty(&ep->queue)) {
+ dev_err(ep->udc->dev, "the %s have no requeue!\n", ep->name);
+ } else {
+ req = list_entry(ep->queue.next, struct qe_req, queue);
+
+ cp = (u8 *)(req->req.buf) + req->req.actual;
+ if (cp) {
+ memcpy(cp, pframe->data, fsize);
+ req->req.actual += fsize;
+ if ((fsize < ep->ep.maxpacket) ||
+ (req->req.actual >= req->req.length)) {
+ if (ep->epnum == 0)
+ ep0_req_complete(ep->udc, req);
+ else
+ done(ep, req, 0);
+ if (list_empty(&ep->queue) && ep->epnum != 0)
+ qe_eprx_nack(ep);
+ }
+ }
+ }
+
+ qe_ep_toggledata01(ep);
+
+ return 0;
+}
+
+static void ep_rx_tasklet(unsigned long data)
+{
+ struct qe_udc *udc = (struct qe_udc *)data;
+ struct qe_ep *ep;
+ struct qe_frame *pframe;
+ struct qe_bd __iomem *bd;
+ unsigned long flags;
+ u32 bdstatus, length;
+ u32 vaddr, i;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ for (i = 1; i < USB_MAX_ENDPOINTS; i++) {
+ ep = &udc->eps[i];
+
+ if (ep->dir == USB_DIR_IN || ep->enable_tasklet == 0) {
+ dev_dbg(udc->dev,
+ "This is a transmit ep or disable tasklet!\n");
+ continue;
+ }
+
+ pframe = ep->rxframe;
+ bd = ep->n_rxbd;
+ bdstatus = in_be32((u32 __iomem *)bd);
+ length = bdstatus & BD_LENGTH_MASK;
+
+ while (!(bdstatus & R_E) && length) {
+ if (list_empty(&ep->queue)) {
+ qe_eprx_nack(ep);
+ dev_dbg(udc->dev,
+ "The rxep have noreq %d\n",
+ ep->has_data);
+ break;
+ }
+
+ if ((bdstatus & R_F) && (bdstatus & R_L)
+ && !(bdstatus & R_ERROR)) {
+ qe_frame_clean(pframe);
+ vaddr = (u32)phys_to_virt(in_be32(&bd->buf));
+ frame_set_data(pframe, (u8 *)vaddr);
+ frame_set_length(pframe,
+ (length - USB_CRC_SIZE));
+ frame_set_status(pframe, FRAME_OK);
+ switch (bdstatus & R_PID) {
+ case R_PID_DATA1:
+ frame_set_info(pframe, PID_DATA1);
+ break;
+ case R_PID_SETUP:
+ frame_set_info(pframe, PID_SETUP);
+ break;
+ default:
+ frame_set_info(pframe, PID_DATA0);
+ break;
+ }
+ /* handle the rx frame */
+ qe_ep_rxframe_handle(ep);
+ } else {
+ dev_err(udc->dev,
+ "error in received frame\n");
+ }
+ /* note: don't clear the rxbd's buffer address */
+ /*clear the length */
+ out_be32((u32 __iomem *)bd, bdstatus & BD_STATUS_MASK);
+ ep->has_data--;
+ if (!(ep->localnack))
+ recycle_one_rxbd(ep);
+
+ /* Get next BD */
+ if (bdstatus & R_W)
+ bd = ep->rxbase;
+ else
+ bd++;
+
+ bdstatus = in_be32((u32 __iomem *)bd);
+ length = bdstatus & BD_LENGTH_MASK;
+ }
+
+ ep->n_rxbd = bd;
+
+ if (ep->localnack)
+ ep_recycle_rxbds(ep);
+
+ ep->enable_tasklet = 0;
+ } /* for i=1 */
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+static int qe_ep_rx(struct qe_ep *ep)
+{
+ struct qe_udc *udc;
+ struct qe_frame *pframe;
+ struct qe_bd __iomem *bd;
+ u16 swoffs, ucoffs, emptybds;
+
+ udc = ep->udc;
+ pframe = ep->rxframe;
+
+ if (ep->dir == USB_DIR_IN) {
+ dev_err(udc->dev, "transmit ep in rx function\n");
+ return -EINVAL;
+ }
+
+ bd = ep->n_rxbd;
+
+ swoffs = (u16)(bd - ep->rxbase);
+ ucoffs = (u16)((in_be16(&udc->ep_param[ep->epnum]->rbptr) -
+ in_be16(&udc->ep_param[ep->epnum]->rbase)) >> 3);
+ if (swoffs < ucoffs)
+ emptybds = USB_BDRING_LEN_RX - ucoffs + swoffs;
+ else
+ emptybds = swoffs - ucoffs;
+
+ if (emptybds < MIN_EMPTY_BDS) {
+ qe_eprx_nack(ep);
+ ep->localnack = 1;
+ dev_vdbg(udc->dev, "%d empty bds, send NACK\n", emptybds);
+ }
+ ep->has_data = USB_BDRING_LEN_RX - emptybds;
+
+ if (list_empty(&ep->queue)) {
+ qe_eprx_nack(ep);
+ dev_vdbg(udc->dev, "The rxep have no req queued with %d BDs\n",
+ ep->has_data);
+ return 0;
+ }
+
+ tasklet_schedule(&udc->rx_tasklet);
+ ep->enable_tasklet = 1;
+
+ return 0;
+}
+
+/* send data from a frame, no matter what tx_req */
+static int qe_ep_tx(struct qe_ep *ep, struct qe_frame *frame)
+{
+ struct qe_udc *udc = ep->udc;
+ struct qe_bd __iomem *bd;
+ u16 saveusbmr;
+ u32 bdstatus, pidmask;
+ u32 paddr;
+
+ if (ep->dir == USB_DIR_OUT) {
+ dev_err(udc->dev, "receive ep passed to tx function\n");
+ return -EINVAL;
+ }
+
+ /* Disable the Tx interrupt */
+ saveusbmr = in_be16(&udc->usb_regs->usb_usbmr);
+ out_be16(&udc->usb_regs->usb_usbmr,
+ saveusbmr & ~(USB_E_TXB_MASK | USB_E_TXE_MASK));
+
+ bd = ep->n_txbd;
+ bdstatus = in_be32((u32 __iomem *)bd);
+
+ if (!(bdstatus & (T_R | BD_LENGTH_MASK))) {
+ if (frame_get_length(frame) == 0) {
+ frame_set_data(frame, udc->nullbuf);
+ frame_set_length(frame, 2);
+ frame->info |= (ZLP | NO_CRC);
+ dev_vdbg(udc->dev, "the frame size = 0\n");
+ }
+ paddr = virt_to_phys((void *)frame->data);
+ out_be32(&bd->buf, paddr);
+ bdstatus = (bdstatus&T_W);
+ if (!(frame_get_info(frame) & NO_CRC))
+ bdstatus |= T_R | T_I | T_L | T_TC
+ | frame_get_length(frame);
+ else
+ bdstatus |= T_R | T_I | T_L | frame_get_length(frame);
+
+ /* if the packet is a ZLP in status phase */
+ if ((ep->epnum == 0) && (udc->ep0_state == DATA_STATE_NEED_ZLP))
+ ep->data01 = 0x1;
+
+ if (ep->data01) {
+ pidmask = T_PID_DATA1;
+ frame->info |= PID_DATA1;
+ } else {
+ pidmask = T_PID_DATA0;
+ frame->info |= PID_DATA0;
+ }
+ bdstatus |= T_CNF;
+ bdstatus |= pidmask;
+ out_be32((u32 __iomem *)bd, bdstatus);
+ qe_ep_filltxfifo(ep);
+
+ /* enable the TX interrupt */
+ out_be16(&udc->usb_regs->usb_usbmr, saveusbmr);
+
+ qe_ep_toggledata01(ep);
+ if (bdstatus & T_W)
+ ep->n_txbd = ep->txbase;
+ else
+ ep->n_txbd++;
+
+ return 0;
+ } else {
+ out_be16(&udc->usb_regs->usb_usbmr, saveusbmr);
+ dev_vdbg(udc->dev, "The tx bd is not ready!\n");
+ return -EBUSY;
+ }
+}
+
+/* when a bd was transmitted, the function can
+ * handle the tx_req, not include ep0 */
+static int txcomplete(struct qe_ep *ep, unsigned char restart)
+{
+ if (ep->tx_req != NULL) {
+ if (!restart) {
+ int asent = ep->last;
+ ep->sent += asent;
+ ep->last -= asent;
+ } else {
+ ep->last = 0;
+ }
+
+ /* a request already were transmitted completely */
+ if ((ep->tx_req->req.length - ep->sent) <= 0) {
+ ep->tx_req->req.actual = (unsigned int)ep->sent;
+ done(ep, ep->tx_req, 0);
+ ep->tx_req = NULL;
+ ep->last = 0;
+ ep->sent = 0;
+ }
+ }
+
+ /* we should gain a new tx_req fot this endpoint */
+ if (ep->tx_req == NULL) {
+ if (!list_empty(&ep->queue)) {
+ ep->tx_req = list_entry(ep->queue.next, struct qe_req,
+ queue);
+ ep->last = 0;
+ ep->sent = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* give a frame and a tx_req, send some data */
+static int qe_usb_senddata(struct qe_ep *ep, struct qe_frame *frame)
+{
+ unsigned int size;
+ u8 *buf;
+
+ qe_frame_clean(frame);
+ size = min_t(u32, (ep->tx_req->req.length - ep->sent),
+ ep->ep.maxpacket);
+ buf = (u8 *)ep->tx_req->req.buf + ep->sent;
+ if (buf && size) {
+ ep->last = size;
+ frame_set_data(frame, buf);
+ frame_set_length(frame, size);
+ frame_set_status(frame, FRAME_OK);
+ frame_set_info(frame, 0);
+ return qe_ep_tx(ep, frame);
+ }
+ return -EIO;
+}
+
+/* give a frame struct,send a ZLP */
+static int sendnulldata(struct qe_ep *ep, struct qe_frame *frame, uint infor)
+{
+ struct qe_udc *udc = ep->udc;
+
+ if (frame == NULL)
+ return -ENODEV;
+
+ qe_frame_clean(frame);
+ frame_set_data(frame, (u8 *)udc->nullbuf);
+ frame_set_length(frame, 2);
+ frame_set_status(frame, FRAME_OK);
+ frame_set_info(frame, (ZLP | NO_CRC | infor));
+
+ return qe_ep_tx(ep, frame);
+}
+
+static int frame_create_tx(struct qe_ep *ep, struct qe_frame *frame)
+{
+ struct qe_req *req = ep->tx_req;
+ int reval;
+
+ if (req == NULL)
+ return -ENODEV;
+
+ if ((req->req.length - ep->sent) > 0)
+ reval = qe_usb_senddata(ep, frame);
+ else
+ reval = sendnulldata(ep, frame, 0);
+
+ return reval;
+}
+
+/* if direction is DIR_IN, the status is Device->Host
+ * if direction is DIR_OUT, the status transaction is Device<-Host
+ * in status phase, udc create a request and gain status */
+static int ep0_prime_status(struct qe_udc *udc, int direction)
+{
+
+ struct qe_ep *ep = &udc->eps[0];
+
+ if (direction == USB_DIR_IN) {
+ udc->ep0_state = DATA_STATE_NEED_ZLP;
+ udc->ep0_dir = USB_DIR_IN;
+ sendnulldata(ep, ep->txframe, SETUP_STATUS | NO_REQ);
+ } else {
+ udc->ep0_dir = USB_DIR_OUT;
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+ }
+
+ return 0;
+}
+
+/* a request complete in ep0, whether gadget request or udc request */
+static void ep0_req_complete(struct qe_udc *udc, struct qe_req *req)
+{
+ struct qe_ep *ep = &udc->eps[0];
+ /* because usb and ep's status already been set in ch9setaddress() */
+
+ switch (udc->ep0_state) {
+ case DATA_STATE_XMIT:
+ done(ep, req, 0);
+ /* receive status phase */
+ if (ep0_prime_status(udc, USB_DIR_OUT))
+ qe_ep0_stall(udc);
+ break;
+
+ case DATA_STATE_NEED_ZLP:
+ done(ep, req, 0);
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+
+ case DATA_STATE_RECV:
+ done(ep, req, 0);
+ /* send status phase */
+ if (ep0_prime_status(udc, USB_DIR_IN))
+ qe_ep0_stall(udc);
+ break;
+
+ case WAIT_FOR_OUT_STATUS:
+ done(ep, req, 0);
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+
+ case WAIT_FOR_SETUP:
+ dev_vdbg(udc->dev, "Unexpected interrupt\n");
+ break;
+
+ default:
+ qe_ep0_stall(udc);
+ break;
+ }
+}
+
+static int ep0_txcomplete(struct qe_ep *ep, unsigned char restart)
+{
+ struct qe_req *tx_req = NULL;
+ struct qe_frame *frame = ep->txframe;
+
+ if ((frame_get_info(frame) & (ZLP | NO_REQ)) == (ZLP | NO_REQ)) {
+ if (!restart)
+ ep->udc->ep0_state = WAIT_FOR_SETUP;
+ else
+ sendnulldata(ep, ep->txframe, SETUP_STATUS | NO_REQ);
+ return 0;
+ }
+
+ tx_req = ep->tx_req;
+ if (tx_req != NULL) {
+ if (!restart) {
+ int asent = ep->last;
+ ep->sent += asent;
+ ep->last -= asent;
+ } else {
+ ep->last = 0;
+ }
+
+ /* a request already were transmitted completely */
+ if ((ep->tx_req->req.length - ep->sent) <= 0) {
+ ep->tx_req->req.actual = (unsigned int)ep->sent;
+ ep0_req_complete(ep->udc, ep->tx_req);
+ ep->tx_req = NULL;
+ ep->last = 0;
+ ep->sent = 0;
+ }
+ } else {
+ dev_vdbg(ep->udc->dev, "the ep0_controller have no req\n");
+ }
+
+ return 0;
+}
+
+static int ep0_txframe_handle(struct qe_ep *ep)
+{
+ /* if have error, transmit again */
+ if (frame_get_status(ep->txframe) & FRAME_ERROR) {
+ qe_ep_flushtxfifo(ep);
+ dev_vdbg(ep->udc->dev, "The EP0 transmit data have error!\n");
+ if (frame_get_info(ep->txframe) & PID_DATA0)
+ ep->data01 = 0;
+ else
+ ep->data01 = 1;
+
+ ep0_txcomplete(ep, 1);
+ } else
+ ep0_txcomplete(ep, 0);
+
+ frame_create_tx(ep, ep->txframe);
+ return 0;
+}
+
+static int qe_ep0_txconf(struct qe_ep *ep)
+{
+ struct qe_bd __iomem *bd;
+ struct qe_frame *pframe;
+ u32 bdstatus;
+
+ bd = ep->c_txbd;
+ bdstatus = in_be32((u32 __iomem *)bd);
+ while (!(bdstatus & T_R) && (bdstatus & ~T_W)) {
+ pframe = ep->txframe;
+
+ /* clear and recycle the BD */
+ out_be32((u32 __iomem *)bd, bdstatus & T_W);
+ out_be32(&bd->buf, 0);
+ if (bdstatus & T_W)
+ ep->c_txbd = ep->txbase;
+ else
+ ep->c_txbd++;
+
+ if (ep->c_txbd == ep->n_txbd) {
+ if (bdstatus & DEVICE_T_ERROR) {
+ frame_set_status(pframe, FRAME_ERROR);
+ if (bdstatus & T_TO)
+ pframe->status |= TX_ER_TIMEOUT;
+ if (bdstatus & T_UN)
+ pframe->status |= TX_ER_UNDERUN;
+ }
+ ep0_txframe_handle(ep);
+ }
+
+ bd = ep->c_txbd;
+ bdstatus = in_be32((u32 __iomem *)bd);
+ }
+
+ return 0;
+}
+
+static int ep_txframe_handle(struct qe_ep *ep)
+{
+ if (frame_get_status(ep->txframe) & FRAME_ERROR) {
+ qe_ep_flushtxfifo(ep);
+ dev_vdbg(ep->udc->dev, "The EP0 transmit data have error!\n");
+ if (frame_get_info(ep->txframe) & PID_DATA0)
+ ep->data01 = 0;
+ else
+ ep->data01 = 1;
+
+ txcomplete(ep, 1);
+ } else
+ txcomplete(ep, 0);
+
+ frame_create_tx(ep, ep->txframe); /* send the data */
+ return 0;
+}
+
+/* confirm the already trainsmited bd */
+static int qe_ep_txconf(struct qe_ep *ep)
+{
+ struct qe_bd __iomem *bd;
+ struct qe_frame *pframe = NULL;
+ u32 bdstatus;
+ unsigned char breakonrxinterrupt = 0;
+
+ bd = ep->c_txbd;
+ bdstatus = in_be32((u32 __iomem *)bd);
+ while (!(bdstatus & T_R) && (bdstatus & ~T_W)) {
+ pframe = ep->txframe;
+ if (bdstatus & DEVICE_T_ERROR) {
+ frame_set_status(pframe, FRAME_ERROR);
+ if (bdstatus & T_TO)
+ pframe->status |= TX_ER_TIMEOUT;
+ if (bdstatus & T_UN)
+ pframe->status |= TX_ER_UNDERUN;
+ }
+
+ /* clear and recycle the BD */
+ out_be32((u32 __iomem *)bd, bdstatus & T_W);
+ out_be32(&bd->buf, 0);
+ if (bdstatus & T_W)
+ ep->c_txbd = ep->txbase;
+ else
+ ep->c_txbd++;
+
+ /* handle the tx frame */
+ ep_txframe_handle(ep);
+ bd = ep->c_txbd;
+ bdstatus = in_be32((u32 __iomem *)bd);
+ }
+ if (breakonrxinterrupt)
+ return -EIO;
+ else
+ return 0;
+}
+
+/* Add a request in queue, and try to transmit a packet */
+static int ep_req_send(struct qe_ep *ep, struct qe_req *req)
+{
+ int reval = 0;
+
+ if (ep->tx_req == NULL) {
+ ep->sent = 0;
+ ep->last = 0;
+ txcomplete(ep, 0); /* can gain a new tx_req */
+ reval = frame_create_tx(ep, ep->txframe);
+ }
+ return reval;
+}
+
+/* Maybe this is a good ideal */
+static int ep_req_rx(struct qe_ep *ep, struct qe_req *req)
+{
+ struct qe_udc *udc = ep->udc;
+ struct qe_frame *pframe = NULL;
+ struct qe_bd __iomem *bd;
+ u32 bdstatus, length;
+ u32 vaddr, fsize;
+ u8 *cp;
+ u8 finish_req = 0;
+ u8 framepid;
+
+ if (list_empty(&ep->queue)) {
+ dev_vdbg(udc->dev, "the req already finish!\n");
+ return 0;
+ }
+ pframe = ep->rxframe;
+
+ bd = ep->n_rxbd;
+ bdstatus = in_be32((u32 __iomem *)bd);
+ length = bdstatus & BD_LENGTH_MASK;
+
+ while (!(bdstatus & R_E) && length) {
+ if (finish_req)
+ break;
+ if ((bdstatus & R_F) && (bdstatus & R_L)
+ && !(bdstatus & R_ERROR)) {
+ qe_frame_clean(pframe);
+ vaddr = (u32)phys_to_virt(in_be32(&bd->buf));
+ frame_set_data(pframe, (u8 *)vaddr);
+ frame_set_length(pframe, (length - USB_CRC_SIZE));
+ frame_set_status(pframe, FRAME_OK);
+ switch (bdstatus & R_PID) {
+ case R_PID_DATA1:
+ frame_set_info(pframe, PID_DATA1); break;
+ default:
+ frame_set_info(pframe, PID_DATA0); break;
+ }
+ /* handle the rx frame */
+
+ if (frame_get_info(pframe) & PID_DATA1)
+ framepid = 0x1;
+ else
+ framepid = 0;
+
+ if (framepid != ep->data01) {
+ dev_vdbg(udc->dev, "the data01 error!\n");
+ } else {
+ fsize = frame_get_length(pframe);
+
+ cp = (u8 *)(req->req.buf) + req->req.actual;
+ if (cp) {
+ memcpy(cp, pframe->data, fsize);
+ req->req.actual += fsize;
+ if ((fsize < ep->ep.maxpacket)
+ || (req->req.actual >=
+ req->req.length)) {
+ finish_req = 1;
+ done(ep, req, 0);
+ if (list_empty(&ep->queue))
+ qe_eprx_nack(ep);
+ }
+ }
+ qe_ep_toggledata01(ep);
+ }
+ } else {
+ dev_err(udc->dev, "The receive frame with error!\n");
+ }
+
+ /* note: don't clear the rxbd's buffer address *
+ * only Clear the length */
+ out_be32((u32 __iomem *)bd, (bdstatus & BD_STATUS_MASK));
+ ep->has_data--;
+
+ /* Get next BD */
+ if (bdstatus & R_W)
+ bd = ep->rxbase;
+ else
+ bd++;
+
+ bdstatus = in_be32((u32 __iomem *)bd);
+ length = bdstatus & BD_LENGTH_MASK;
+ }
+
+ ep->n_rxbd = bd;
+ ep_recycle_rxbds(ep);
+
+ return 0;
+}
+
+/* only add the request in queue */
+static int ep_req_receive(struct qe_ep *ep, struct qe_req *req)
+{
+ if (ep->state == EP_STATE_NACK) {
+ if (ep->has_data <= 0) {
+ /* Enable rx and unmask rx interrupt */
+ qe_eprx_normal(ep);
+ } else {
+ /* Copy the exist BD data */
+ ep_req_rx(ep, req);
+ }
+ }
+
+ return 0;
+}
+
+/********************************************************************
+ Internal Used Function End
+********************************************************************/
+
+/*-----------------------------------------------------------------------
+ Endpoint Management Functions For Gadget
+ -----------------------------------------------------------------------*/
+static int qe_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct qe_udc *udc;
+ struct qe_ep *ep;
+ int retval = 0;
+ unsigned char epnum;
+
+ ep = container_of(_ep, struct qe_ep, ep);
+
+ /* catch various bogus parameters */
+ if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] ||
+ (desc->bDescriptorType != USB_DT_ENDPOINT))
+ return -EINVAL;
+
+ udc = ep->udc;
+ if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+
+ epnum = (u8)desc->bEndpointAddress & 0xF;
+
+ retval = qe_ep_init(udc, epnum, desc);
+ if (retval != 0) {
+ cpm_muram_free(cpm_muram_offset(ep->rxbase));
+ dev_dbg(udc->dev, "enable ep%d failed\n", ep->epnum);
+ return -EINVAL;
+ }
+ dev_dbg(udc->dev, "enable ep%d successful\n", ep->epnum);
+ return 0;
+}
+
+static int qe_ep_disable(struct usb_ep *_ep)
+{
+ struct qe_udc *udc;
+ struct qe_ep *ep;
+ unsigned long flags;
+ unsigned int size;
+
+ ep = container_of(_ep, struct qe_ep, ep);
+ udc = ep->udc;
+
+ if (!_ep || !ep->desc) {
+ dev_dbg(udc->dev, "%s not enabled\n", _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ /* Nuke all pending requests (does flush) */
+ nuke(ep, -ESHUTDOWN);
+ ep->desc = NULL;
+ ep->stopped = 1;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ cpm_muram_free(cpm_muram_offset(ep->rxbase));
+
+ if (ep->dir == USB_DIR_OUT)
+ size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) *
+ (USB_BDRING_LEN_RX + 1);
+ else
+ size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) *
+ (USB_BDRING_LEN + 1);
+
+ if (ep->dir != USB_DIR_IN) {
+ kfree(ep->rxframe);
+ if (ep->rxbufmap) {
+ dma_unmap_single(udc_controller->gadget.dev.parent,
+ ep->rxbuf_d, size,
+ DMA_FROM_DEVICE);
+ ep->rxbuf_d = DMA_ADDR_INVALID;
+ } else {
+ dma_sync_single_for_cpu(
+ udc_controller->gadget.dev.parent,
+ ep->rxbuf_d, size,
+ DMA_FROM_DEVICE);
+ }
+ kfree(ep->rxbuffer);
+ }
+
+ if (ep->dir != USB_DIR_OUT)
+ kfree(ep->txframe);
+
+ dev_dbg(udc->dev, "disabled %s OK\n", _ep->name);
+ return 0;
+}
+
+static struct usb_request *qe_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct qe_req *req;
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_ADDR_INVALID;
+
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void qe_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct qe_req *req;
+
+ req = container_of(_req, struct qe_req, req);
+
+ if (_req)
+ kfree(req);
+}
+
+/* queues (submits) an I/O request to an endpoint */
+static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct qe_ep *ep = container_of(_ep, struct qe_ep, ep);
+ struct qe_req *req = container_of(_req, struct qe_req, req);
+ struct qe_udc *udc;
+ unsigned long flags;
+ int reval;
+
+ udc = ep->udc;
+ /* catch various bogus parameters */
+ if (!_req || !req->req.complete || !req->req.buf
+ || !list_empty(&req->queue)) {
+ dev_dbg(udc->dev, "bad params\n");
+ return -EINVAL;
+ }
+ if (!_ep || (!ep->desc && ep_index(ep))) {
+ dev_dbg(udc->dev, "bad ep\n");
+ return -EINVAL;
+ }
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ req->ep = ep;
+
+ /* map virtual address to hardware */
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
+ req->req.buf,
+ req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE :
+ DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE :
+ DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
+
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+
+ list_add_tail(&req->queue, &ep->queue);
+ dev_vdbg(udc->dev, "gadget have request in %s! %d\n",
+ ep->name, req->req.length);
+ spin_lock_irqsave(&udc->lock, flags);
+ /* push the request to device */
+ if (ep_is_in(ep))
+ reval = ep_req_send(ep, req);
+
+ /* EP0 */
+ if (ep_index(ep) == 0 && req->req.length > 0) {
+ if (ep_is_in(ep))
+ udc->ep0_state = DATA_STATE_XMIT;
+ else
+ udc->ep0_state = DATA_STATE_RECV;
+ }
+
+ if (ep->dir == USB_DIR_OUT)
+ reval = ep_req_receive(ep, req);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int qe_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct qe_ep *ep = container_of(_ep, struct qe_ep, ep);
+ struct qe_req *req;
+ unsigned long flags;
+
+ if (!_ep || !_req)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+
+ if (&req->req != _req) {
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return -EINVAL;
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return 0;
+}
+
+/*-----------------------------------------------------------------
+ * modify the endpoint halt feature
+ * @ep: the non-isochronous endpoint being stalled
+ * @value: 1--set halt 0--clear halt
+ * Returns zero, or a negative error code.
+*----------------------------------------------------------------*/
+static int qe_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct qe_ep *ep;
+ unsigned long flags;
+ int status = -EOPNOTSUPP;
+ struct qe_udc *udc;
+
+ ep = container_of(_ep, struct qe_ep, ep);
+ if (!_ep || !ep->desc) {
+ status = -EINVAL;
+ goto out;
+ }
+
+ udc = ep->udc;
+ /* Attempt to halt IN ep will fail if any transfer requests
+ * are still queue */
+ if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
+ status = -EAGAIN;
+ goto out;
+ }
+
+ status = 0;
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ qe_eptx_stall_change(ep, value);
+ qe_eprx_stall_change(ep, value);
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+ if (ep->epnum == 0) {
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ }
+
+ /* set data toggle to DATA0 on clear halt */
+ if (value == 0)
+ ep->data01 = 0;
+out:
+ dev_vdbg(udc->dev, "%s %s halt stat %d\n", ep->ep.name,
+ value ? "set" : "clear", status);
+
+ return status;
+}
+
+static struct usb_ep_ops qe_ep_ops = {
+ .enable = qe_ep_enable,
+ .disable = qe_ep_disable,
+
+ .alloc_request = qe_alloc_request,
+ .free_request = qe_free_request,
+
+ .queue = qe_ep_queue,
+ .dequeue = qe_ep_dequeue,
+
+ .set_halt = qe_ep_set_halt,
+};
+
+/*------------------------------------------------------------------------
+ Gadget Driver Layer Operations
+ ------------------------------------------------------------------------*/
+
+/* Get the current frame number */
+static int qe_get_frame(struct usb_gadget *gadget)
+{
+ u16 tmp;
+
+ tmp = in_be16(&udc_controller->usb_param->frame_n);
+ if (tmp & 0x8000)
+ tmp = tmp & 0x07ff;
+ else
+ tmp = -EINVAL;
+
+ return (int)tmp;
+}
+
+/* Tries to wake up the host connected to this gadget
+ *
+ * Return : 0-success
+ * Negative-this feature not enabled by host or not supported by device hw
+ */
+static int qe_wakeup(struct usb_gadget *gadget)
+{
+ return -ENOTSUPP;
+}
+
+/* Notify controller that VBUS is powered, Called by whatever
+ detects VBUS sessions */
+static int qe_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ return -ENOTSUPP;
+}
+
+/* constrain controller's VBUS power usage
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume. For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static int qe_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ return -ENOTSUPP;
+}
+
+/* Change Data+ pullup status
+ * this func is used by usb_gadget_connect/disconnect
+ */
+static int qe_pullup(struct usb_gadget *gadget, int is_on)
+{
+ return -ENOTSUPP;
+}
+
+/* defined in usb_gadget.h */
+static struct usb_gadget_ops qe_gadget_ops = {
+ .get_frame = qe_get_frame,
+ .wakeup = qe_wakeup,
+/* .set_selfpowered = qe_set_selfpowered,*/ /* always selfpowered */
+ .vbus_session = qe_vbus_session,
+ .vbus_draw = qe_vbus_draw,
+ .pullup = qe_pullup,
+};
+
+/*-------------------------------------------------------------------------
+ USB ep0 Setup process in BUS Enumeration
+ -------------------------------------------------------------------------*/
+static int udc_reset_ep_queue(struct qe_udc *udc, u8 pipe)
+{
+ struct qe_ep *ep = &udc->eps[pipe];
+
+ nuke(ep, -ECONNRESET);
+ ep->tx_req = NULL;
+ return 0;
+}
+
+static int reset_queues(struct qe_udc *udc)
+{
+ u8 pipe;
+
+ for (pipe = 0; pipe < USB_MAX_ENDPOINTS; pipe++)
+ udc_reset_ep_queue(udc, pipe);
+
+ /* report disconnect; the driver is already quiesced */
+ spin_unlock(&udc->lock);
+ udc->driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+
+ return 0;
+}
+
+static void ch9setaddress(struct qe_udc *udc, u16 value, u16 index,
+ u16 length)
+{
+ /* Save the new address to device struct */
+ udc->device_address = (u8) value;
+ /* Update usb state */
+ udc->usb_state = USB_STATE_ADDRESS;
+
+ /* Status phase , send a ZLP */
+ if (ep0_prime_status(udc, USB_DIR_IN))
+ qe_ep0_stall(udc);
+}
+
+static void ownercomplete(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct qe_req *req = container_of(_req, struct qe_req, req);
+
+ req->req.buf = NULL;
+ kfree(req);
+}
+
+static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value,
+ u16 index, u16 length)
+{
+ u16 usb_status = 0;
+ struct qe_req *req;
+ struct qe_ep *ep;
+ int status = 0;
+
+ ep = &udc->eps[0];
+ if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ /* Get device status */
+ usb_status = 1 << USB_DEVICE_SELF_POWERED;
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+ /* Get interface status */
+ /* We don't have interface information in udc driver */
+ usb_status = 0;
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+ /* Get endpoint status */
+ int pipe = index & USB_ENDPOINT_NUMBER_MASK;
+ struct qe_ep *target_ep = &udc->eps[pipe];
+ u16 usep;
+
+ /* stall if endpoint doesn't exist */
+ if (!target_ep->desc)
+ goto stall;
+
+ usep = in_be16(&udc->usb_regs->usb_usep[pipe]);
+ if (index & USB_DIR_IN) {
+ if (target_ep->dir != USB_DIR_IN)
+ goto stall;
+ if ((usep & USB_THS_MASK) == USB_THS_STALL)
+ usb_status = 1 << USB_ENDPOINT_HALT;
+ } else {
+ if (target_ep->dir != USB_DIR_OUT)
+ goto stall;
+ if ((usep & USB_RHS_MASK) == USB_RHS_STALL)
+ usb_status = 1 << USB_ENDPOINT_HALT;
+ }
+ }
+
+ req = container_of(qe_alloc_request(&ep->ep, GFP_KERNEL),
+ struct qe_req, req);
+ req->req.length = 2;
+ req->req.buf = udc->statusbuf;
+ *(u16 *)req->req.buf = cpu_to_le16(usb_status);
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = ownercomplete;
+
+ udc->ep0_dir = USB_DIR_IN;
+
+ /* data phase */
+ status = qe_ep_queue(&ep->ep, &req->req, GFP_ATOMIC);
+
+ if (status == 0)
+ return;
+stall:
+ dev_err(udc->dev, "Can't respond to getstatus request \n");
+ qe_ep0_stall(udc);
+}
+
+/* only handle the setup request, suppose the device in normal status */
+static void setup_received_handle(struct qe_udc *udc,
+ struct usb_ctrlrequest *setup)
+{
+ /* Fix Endian (udc->local_setup_buff is cpu Endian now)*/
+ u16 wValue = le16_to_cpu(setup->wValue);
+ u16 wIndex = le16_to_cpu(setup->wIndex);
+ u16 wLength = le16_to_cpu(setup->wLength);
+
+ /* clear the previous request in the ep0 */
+ udc_reset_ep_queue(udc, 0);
+
+ if (setup->bRequestType & USB_DIR_IN)
+ udc->ep0_dir = USB_DIR_IN;
+ else
+ udc->ep0_dir = USB_DIR_OUT;
+
+ switch (setup->bRequest) {
+ case USB_REQ_GET_STATUS:
+ /* Data+Status phase form udc */
+ if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
+ != (USB_DIR_IN | USB_TYPE_STANDARD))
+ break;
+ ch9getstatus(udc, setup->bRequestType, wValue, wIndex,
+ wLength);
+ return;
+
+ case USB_REQ_SET_ADDRESS:
+ /* Status phase from udc */
+ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_DEVICE))
+ break;
+ ch9setaddress(udc, wValue, wIndex, wLength);
+ return;
+
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ /* Requests with no data phase, status phase from udc */
+ if ((setup->bRequestType & USB_TYPE_MASK)
+ != USB_TYPE_STANDARD)
+ break;
+
+ if ((setup->bRequestType & USB_RECIP_MASK)
+ == USB_RECIP_ENDPOINT) {
+ int pipe = wIndex & USB_ENDPOINT_NUMBER_MASK;
+ struct qe_ep *ep;
+
+ if (wValue != 0 || wLength != 0
+ || pipe > USB_MAX_ENDPOINTS)
+ break;
+ ep = &udc->eps[pipe];
+
+ spin_unlock(&udc->lock);
+ qe_ep_set_halt(&ep->ep,
+ (setup->bRequest == USB_REQ_SET_FEATURE)
+ ? 1 : 0);
+ spin_lock(&udc->lock);
+ }
+
+ ep0_prime_status(udc, USB_DIR_IN);
+
+ return;
+
+ default:
+ break;
+ }
+
+ if (wLength) {
+ /* Data phase from gadget, status phase from udc */
+ if (setup->bRequestType & USB_DIR_IN) {
+ udc->ep0_state = DATA_STATE_XMIT;
+ udc->ep0_dir = USB_DIR_IN;
+ } else {
+ udc->ep0_state = DATA_STATE_RECV;
+ udc->ep0_dir = USB_DIR_OUT;
+ }
+ spin_unlock(&udc->lock);
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ qe_ep0_stall(udc);
+ spin_lock(&udc->lock);
+ } else {
+ /* No data phase, IN status from gadget */
+ udc->ep0_dir = USB_DIR_IN;
+ spin_unlock(&udc->lock);
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ qe_ep0_stall(udc);
+ spin_lock(&udc->lock);
+ udc->ep0_state = DATA_STATE_NEED_ZLP;
+ }
+}
+
+/*-------------------------------------------------------------------------
+ USB Interrupt handlers
+ -------------------------------------------------------------------------*/
+static void suspend_irq(struct qe_udc *udc)
+{
+ udc->resume_state = udc->usb_state;
+ udc->usb_state = USB_STATE_SUSPENDED;
+
+ /* report suspend to the driver ,serial.c not support this*/
+ if (udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+}
+
+static void resume_irq(struct qe_udc *udc)
+{
+ udc->usb_state = udc->resume_state;
+ udc->resume_state = 0;
+
+ /* report resume to the driver , serial.c not support this*/
+ if (udc->driver->resume)
+ udc->driver->resume(&udc->gadget);
+}
+
+static void idle_irq(struct qe_udc *udc)
+{
+ u8 usbs;
+
+ usbs = in_8(&udc->usb_regs->usb_usbs);
+ if (usbs & USB_IDLE_STATUS_MASK) {
+ if ((udc->usb_state) != USB_STATE_SUSPENDED)
+ suspend_irq(udc);
+ } else {
+ if (udc->usb_state == USB_STATE_SUSPENDED)
+ resume_irq(udc);
+ }
+}
+
+static int reset_irq(struct qe_udc *udc)
+{
+ unsigned char i;
+
+ qe_usb_disable();
+ out_8(&udc->usb_regs->usb_usadr, 0);
+
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+ if (udc->eps[i].init)
+ qe_ep_reset(udc, i);
+ }
+
+ reset_queues(udc);
+ udc->usb_state = USB_STATE_DEFAULT;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = USB_DIR_OUT;
+ qe_usb_enable();
+ return 0;
+}
+
+static int bsy_irq(struct qe_udc *udc)
+{
+ return 0;
+}
+
+static int txe_irq(struct qe_udc *udc)
+{
+ return 0;
+}
+
+/* ep0 tx interrupt also in here */
+static int tx_irq(struct qe_udc *udc)
+{
+ struct qe_ep *ep;
+ struct qe_bd __iomem *bd;
+ int i, res = 0;
+
+ if ((udc->usb_state == USB_STATE_ADDRESS)
+ && (in_8(&udc->usb_regs->usb_usadr) == 0))
+ out_8(&udc->usb_regs->usb_usadr, udc->device_address);
+
+ for (i = (USB_MAX_ENDPOINTS-1); ((i >= 0) && (res == 0)); i--) {
+ ep = &udc->eps[i];
+ if (ep && ep->init && (ep->dir != USB_DIR_OUT)) {
+ bd = ep->c_txbd;
+ if (!(in_be32((u32 __iomem *)bd) & T_R)
+ && (in_be32(&bd->buf))) {
+ /* confirm the transmitted bd */
+ if (ep->epnum == 0)
+ res = qe_ep0_txconf(ep);
+ else
+ res = qe_ep_txconf(ep);
+ }
+ }
+ }
+ return res;
+}
+
+
+/* setup packect's rx is handle in the function too */
+static void rx_irq(struct qe_udc *udc)
+{
+ struct qe_ep *ep;
+ struct qe_bd __iomem *bd;
+ int i;
+
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+ ep = &udc->eps[i];
+ if (ep && ep->init && (ep->dir != USB_DIR_IN)) {
+ bd = ep->n_rxbd;
+ if (!(in_be32((u32 __iomem *)bd) & R_E)
+ && (in_be32(&bd->buf))) {
+ if (ep->epnum == 0) {
+ qe_ep0_rx(udc);
+ } else {
+ /*non-setup package receive*/
+ qe_ep_rx(ep);
+ }
+ }
+ }
+ }
+}
+
+static irqreturn_t qe_udc_irq(int irq, void *_udc)
+{
+ struct qe_udc *udc = (struct qe_udc *)_udc;
+ u16 irq_src;
+ irqreturn_t status = IRQ_NONE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ irq_src = in_be16(&udc->usb_regs->usb_usber) &
+ in_be16(&udc->usb_regs->usb_usbmr);
+ /* Clear notification bits */
+ out_be16(&udc->usb_regs->usb_usber, irq_src);
+ /* USB Interrupt */
+ if (irq_src & USB_E_IDLE_MASK) {
+ idle_irq(udc);
+ irq_src &= ~USB_E_IDLE_MASK;
+ status = IRQ_HANDLED;
+ }
+
+ if (irq_src & USB_E_TXB_MASK) {
+ tx_irq(udc);
+ irq_src &= ~USB_E_TXB_MASK;
+ status = IRQ_HANDLED;
+ }
+
+ if (irq_src & USB_E_RXB_MASK) {
+ rx_irq(udc);
+ irq_src &= ~USB_E_RXB_MASK;
+ status = IRQ_HANDLED;
+ }
+
+ if (irq_src & USB_E_RESET_MASK) {
+ reset_irq(udc);
+ irq_src &= ~USB_E_RESET_MASK;
+ status = IRQ_HANDLED;
+ }
+
+ if (irq_src & USB_E_BSY_MASK) {
+ bsy_irq(udc);
+ irq_src &= ~USB_E_BSY_MASK;
+ status = IRQ_HANDLED;
+ }
+
+ if (irq_src & USB_E_TXE_MASK) {
+ txe_irq(udc);
+ irq_src &= ~USB_E_TXE_MASK;
+ status = IRQ_HANDLED;
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return status;
+}
+
+/*-------------------------------------------------------------------------
+ Gadget driver register and unregister.
+ --------------------------------------------------------------------------*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ int retval;
+ unsigned long flags = 0;
+
+ /* standard operations */
+ if (!udc_controller)
+ return -ENODEV;
+
+ if (!driver || (driver->speed != USB_SPEED_FULL
+ && driver->speed != USB_SPEED_HIGH)
+ || !driver->bind || !driver->disconnect
+ || !driver->setup)
+ return -EINVAL;
+
+ if (udc_controller->driver)
+ return -EBUSY;
+
+ /* lock is needed but whether should use this lock or another */
+ spin_lock_irqsave(&udc_controller->lock, flags);
+
+ driver->driver.bus = NULL;
+ /* hook up the driver */
+ udc_controller->driver = driver;
+ udc_controller->gadget.dev.driver = &driver->driver;
+ udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed);
+ spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+ retval = driver->bind(&udc_controller->gadget);
+ if (retval) {
+ dev_err(udc_controller->dev, "bind to %s --> %d",
+ driver->driver.name, retval);
+ udc_controller->gadget.dev.driver = NULL;
+ udc_controller->driver = NULL;
+ return retval;
+ }
+
+ /* Enable IRQ reg and Set usbcmd reg EN bit */
+ qe_usb_enable();
+
+ out_be16(&udc_controller->usb_regs->usb_usber, 0xffff);
+ out_be16(&udc_controller->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE);
+ udc_controller->usb_state = USB_STATE_ATTACHED;
+ udc_controller->ep0_state = WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = USB_DIR_OUT;
+ dev_info(udc_controller->dev, "%s bind to driver %s \n",
+ udc_controller->gadget.name, driver->driver.name);
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct qe_ep *loop_ep;
+ unsigned long flags;
+
+ if (!udc_controller)
+ return -ENODEV;
+
+ if (!driver || driver != udc_controller->driver)
+ return -EINVAL;
+
+ /* stop usb controller, disable intr */
+ qe_usb_disable();
+
+ /* in fact, no needed */
+ udc_controller->usb_state = USB_STATE_ATTACHED;
+ udc_controller->ep0_state = WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = 0;
+
+ /* stand operation */
+ spin_lock_irqsave(&udc_controller->lock, flags);
+ udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+ nuke(&udc_controller->eps[0], -ESHUTDOWN);
+ list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list,
+ ep.ep_list)
+ nuke(loop_ep, -ESHUTDOWN);
+ spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+ /* unbind gadget and unhook driver. */
+ driver->unbind(&udc_controller->gadget);
+ udc_controller->gadget.dev.driver = NULL;
+ udc_controller->driver = NULL;
+
+ dev_info(udc_controller->dev, "unregistered gadget driver '%s'\r\n",
+ driver->driver.name);
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/* udc structure's alloc and setup, include ep-param alloc */
+static struct qe_udc __devinit *qe_udc_config(struct of_device *ofdev)
+{
+ struct qe_udc *udc;
+ struct device_node *np = ofdev->node;
+ unsigned int tmp_addr = 0;
+ struct usb_device_para __iomem *usbpram;
+ unsigned int i;
+ u64 size;
+ u32 offset;
+
+ udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+ if (udc == NULL) {
+ dev_err(&ofdev->dev, "malloc udc failed\n");
+ goto cleanup;
+ }
+
+ udc->dev = &ofdev->dev;
+
+ /* get default address of usb parameter in MURAM from device tree */
+ offset = *of_get_address(np, 1, &size, NULL);
+ udc->usb_param = cpm_muram_addr(offset);
+ memset_io(udc->usb_param, 0, size);
+
+ usbpram = udc->usb_param;
+ out_be16(&usbpram->frame_n, 0);
+ out_be32(&usbpram->rstate, 0);
+
+ tmp_addr = cpm_muram_alloc((USB_MAX_ENDPOINTS *
+ sizeof(struct usb_ep_para)),
+ USB_EP_PARA_ALIGNMENT);
+
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+ out_be16(&usbpram->epptr[i], (u16)tmp_addr);
+ udc->ep_param[i] = cpm_muram_addr(tmp_addr);
+ tmp_addr += 32;
+ }
+
+ memset_io(udc->ep_param[0], 0,
+ USB_MAX_ENDPOINTS * sizeof(struct usb_ep_para));
+
+ udc->resume_state = USB_STATE_NOTATTACHED;
+ udc->usb_state = USB_STATE_POWERED;
+ udc->ep0_dir = 0;
+
+ spin_lock_init(&udc->lock);
+ return udc;
+
+cleanup:
+ kfree(udc);
+ return NULL;
+}
+
+/* USB Controller register init */
+static int __devinit qe_udc_reg_init(struct qe_udc *udc)
+{
+ struct usb_ctlr __iomem *qe_usbregs;
+ qe_usbregs = udc->usb_regs;
+
+ /* Init the usb register */
+ out_8(&qe_usbregs->usb_usmod, 0x01);
+ out_be16(&qe_usbregs->usb_usbmr, 0);
+ out_8(&qe_usbregs->usb_uscom, 0);
+ out_be16(&qe_usbregs->usb_usber, USBER_ALL_CLEAR);
+
+ return 0;
+}
+
+static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)
+{
+ struct qe_ep *ep = &udc->eps[pipe_num];
+
+ ep->udc = udc;
+ strcpy(ep->name, ep_name[pipe_num]);
+ ep->ep.name = ep_name[pipe_num];
+
+ ep->ep.ops = &qe_ep_ops;
+ ep->stopped = 1;
+ ep->ep.maxpacket = (unsigned short) ~0;
+ ep->desc = NULL;
+ ep->dir = 0xff;
+ ep->epnum = (u8)pipe_num;
+ ep->sent = 0;
+ ep->last = 0;
+ ep->init = 0;
+ ep->rxframe = NULL;
+ ep->txframe = NULL;
+ ep->tx_req = NULL;
+ ep->state = EP_STATE_IDLE;
+ ep->has_data = 0;
+
+ /* the queue lists any req for this ep */
+ INIT_LIST_HEAD(&ep->queue);
+
+ /* gagdet.ep_list used for ep_autoconfig so no ep0*/
+ if (pipe_num != 0)
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+
+ ep->gadget = &udc->gadget;
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * UDC device Driver operation functions *
+ *----------------------------------------------------------------------*/
+static void qe_udc_release(struct device *dev)
+{
+ int i = 0;
+
+ complete(udc_controller->done);
+ cpm_muram_free(cpm_muram_offset(udc_controller->ep_param[0]));
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++)
+ udc_controller->ep_param[i] = NULL;
+
+ kfree(udc_controller);
+ udc_controller = NULL;
+}
+
+/* Driver probe functions */
+static int __devinit qe_udc_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct qe_ep *ep;
+ unsigned int ret = 0;
+ unsigned int i;
+ const void *prop;
+
+ prop = of_get_property(np, "mode", NULL);
+ if (!prop || strcmp(prop, "peripheral"))
+ return -ENODEV;
+
+ /* 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");
+ return -ENOMEM;
+ }
+
+ udc_controller->soc_type = (unsigned long)match->data;
+ udc_controller->usb_regs = of_iomap(np, 0);
+ if (!udc_controller->usb_regs) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ /* initialize usb hw reg except for regs for EP,
+ * leave usbintr reg untouched*/
+ qe_udc_reg_init(udc_controller);
+
+ /* here comes the stand operations for probe
+ * set the qe_udc->gadget.xxx */
+ udc_controller->gadget.ops = &qe_gadget_ops;
+
+ /* gadget.ep0 is a pointer */
+ udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
+
+ INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
+
+ /* modify in register gadget process */
+ udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* name: Identifies the controller hardware type. */
+ udc_controller->gadget.name = driver_name;
+
+ device_initialize(&udc_controller->gadget.dev);
+
+ strcpy(udc_controller->gadget.dev.bus_id, "gadget");
+
+ udc_controller->gadget.dev.release = qe_udc_release;
+ udc_controller->gadget.dev.parent = &ofdev->dev;
+
+ /* initialize qe_ep struct */
+ for (i = 0; i < USB_MAX_ENDPOINTS ; i++) {
+ /* because the ep type isn't decide here so
+ * qe_ep_init() should be called in ep_enable() */
+
+ /* setup the qe_ep struct and link ep.ep.list
+ * into gadget.ep_list */
+ qe_ep_config(udc_controller, (unsigned char)i);
+ }
+
+ /* ep0 initialization in here */
+ ret = qe_ep_init(udc_controller, 0, &qe_ep0_desc);
+ if (ret)
+ goto err2;
+
+ /* 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");
+ ret = -ENOMEM;
+ goto err3;
+ }
+
+ /* buffer for data of get_status request */
+ udc_controller->statusbuf = kzalloc(2, GFP_KERNEL);
+ if (udc_controller->statusbuf == NULL) {
+ ret = -ENOMEM;
+ goto err4;
+ }
+
+ udc_controller->nullp = virt_to_phys((void *)udc_controller->nullbuf);
+ if (udc_controller->nullp == DMA_ADDR_INVALID) {
+ udc_controller->nullp = dma_map_single(
+ udc_controller->gadget.dev.parent,
+ udc_controller->nullbuf,
+ 256,
+ DMA_TO_DEVICE);
+ udc_controller->nullmap = 1;
+ } else {
+ dma_sync_single_for_device(udc_controller->gadget.dev.parent,
+ udc_controller->nullp, 256,
+ DMA_TO_DEVICE);
+ }
+
+ tasklet_init(&udc_controller->rx_tasklet, ep_rx_tasklet,
+ (unsigned long)udc_controller);
+ /* request irq and disable DR */
+ udc_controller->usb_irq = irq_of_parse_and_map(np, 0);
+
+ ret = request_irq(udc_controller->usb_irq, qe_udc_irq, 0,
+ driver_name, udc_controller);
+ if (ret) {
+ dev_err(udc_controller->dev, "cannot request irq %d err %d \n",
+ udc_controller->usb_irq, ret);
+ goto err5;
+ }
+
+ ret = device_add(&udc_controller->gadget.dev);
+ if (ret)
+ goto err6;
+
+ dev_info(udc_controller->dev,
+ "%s USB controller initialized as device\n",
+ (udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
+ return 0;
+
+err6:
+ free_irq(udc_controller->usb_irq, udc_controller);
+err5:
+ if (udc_controller->nullmap) {
+ dma_unmap_single(udc_controller->gadget.dev.parent,
+ udc_controller->nullp, 256,
+ DMA_TO_DEVICE);
+ udc_controller->nullp = DMA_ADDR_INVALID;
+ } else {
+ dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
+ udc_controller->nullp, 256,
+ DMA_TO_DEVICE);
+ }
+ kfree(udc_controller->statusbuf);
+err4:
+ kfree(udc_controller->nullbuf);
+err3:
+ ep = &udc_controller->eps[0];
+ cpm_muram_free(cpm_muram_offset(ep->rxbase));
+ kfree(ep->rxframe);
+ kfree(ep->rxbuffer);
+ kfree(ep->txframe);
+err2:
+ iounmap(udc_controller->usb_regs);
+err1:
+ kfree(udc_controller);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int qe_udc_suspend(struct of_device *dev, pm_message_t state)
+{
+ return -ENOTSUPP;
+}
+
+static int qe_udc_resume(struct of_device *dev)
+{
+ return -ENOTSUPP;
+}
+#endif
+
+static int __devexit qe_udc_remove(struct of_device *ofdev)
+{
+ struct qe_ep *ep;
+ unsigned int size;
+
+ DECLARE_COMPLETION(done);
+
+ if (!udc_controller)
+ return -ENODEV;
+
+ udc_controller->done = &done;
+ tasklet_disable(&udc_controller->rx_tasklet);
+
+ if (udc_controller->nullmap) {
+ dma_unmap_single(udc_controller->gadget.dev.parent,
+ udc_controller->nullp, 256,
+ DMA_TO_DEVICE);
+ udc_controller->nullp = DMA_ADDR_INVALID;
+ } else {
+ dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
+ udc_controller->nullp, 256,
+ DMA_TO_DEVICE);
+ }
+ kfree(udc_controller->statusbuf);
+ kfree(udc_controller->nullbuf);
+
+ ep = &udc_controller->eps[0];
+ cpm_muram_free(cpm_muram_offset(ep->rxbase));
+ size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (USB_BDRING_LEN + 1);
+
+ kfree(ep->rxframe);
+ if (ep->rxbufmap) {
+ dma_unmap_single(udc_controller->gadget.dev.parent,
+ ep->rxbuf_d, size,
+ DMA_FROM_DEVICE);
+ ep->rxbuf_d = DMA_ADDR_INVALID;
+ } else {
+ dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
+ ep->rxbuf_d, size,
+ DMA_FROM_DEVICE);
+ }
+
+ kfree(ep->rxbuffer);
+ kfree(ep->txframe);
+
+ free_irq(udc_controller->usb_irq, udc_controller);
+
+ tasklet_kill(&udc_controller->rx_tasklet);
+
+ iounmap(udc_controller->usb_regs);
+
+ device_unregister(&udc_controller->gadget.dev);
+ /* wait for release() of gadget.dev to free udc */
+ wait_for_completion(&done);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+static struct of_device_id __devinitdata qe_udc_match[] = {
+ {
+ .compatible = "fsl,mpc8360-qe-usb",
+ .data = (void *)PORT_QE,
+ },
+ {
+ .compatible = "fsl,mpc8272-cpm-usb",
+ .data = (void *)PORT_CPM,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, qe_udc_match);
+
+static struct of_platform_driver udc_driver = {
+ .name = (char *)driver_name,
+ .match_table = qe_udc_match,
+ .probe = qe_udc_probe,
+ .remove = __devexit_p(qe_udc_remove),
+#ifdef CONFIG_PM
+ .suspend = qe_udc_suspend,
+ .resume = qe_udc_resume,
+#endif
+};
+
+static int __init qe_udc_init(void)
+{
+ printk(KERN_INFO "%s: %s, %s\n", driver_name, driver_desc,
+ DRIVER_VERSION);
+ return of_register_platform_driver(&udc_driver);
+}
+
+static void __exit qe_udc_exit(void)
+{
+ of_unregister_platform_driver(&udc_driver);
+}
+
+module_init(qe_udc_init);
+module_exit(qe_udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/fsl_qe_udc.h b/drivers/usb/gadget/fsl_qe_udc.h
new file mode 100644
index 00000000000..31b2710882e
--- /dev/null
+++ b/drivers/usb/gadget/fsl_qe_udc.h
@@ -0,0 +1,437 @@
+/*
+ * drivers/usb/gadget/qe_udc.h
+ *
+ * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Xiaobo Xie <X.Xie@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * Freescale USB device/endpoint management registers
+ *
+ * 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.
+ */
+
+#ifndef __FSL_QE_UDC_H
+#define __FSL_QE_UDC_H
+
+/* SoC type */
+#define PORT_CPM 0
+#define PORT_QE 1
+
+#define USB_MAX_ENDPOINTS 4
+#define USB_MAX_PIPES USB_MAX_ENDPOINTS
+#define USB_EP0_MAX_SIZE 64
+#define USB_MAX_CTRL_PAYLOAD 0x4000
+#define USB_BDRING_LEN 16
+#define USB_BDRING_LEN_RX 256
+#define USB_BDRING_LEN_TX 16
+#define MIN_EMPTY_BDS 128
+#define MAX_DATA_BDS 8
+#define USB_CRC_SIZE 2
+#define USB_DIR_BOTH 0x88
+#define R_BUF_MAXSIZE 0x800
+#define USB_EP_PARA_ALIGNMENT 32
+
+/* USB Mode Register bit define */
+#define USB_MODE_EN 0x01
+#define USB_MODE_HOST 0x02
+#define USB_MODE_TEST 0x04
+#define USB_MODE_SFTE 0x08
+#define USB_MODE_RESUME 0x40
+#define USB_MODE_LSS 0x80
+
+/* USB Slave Address Register Mask */
+#define USB_SLVADDR_MASK 0x7F
+
+/* USB Endpoint register define */
+#define USB_EPNUM_MASK 0xF000
+#define USB_EPNUM_SHIFT 12
+
+#define USB_TRANS_MODE_SHIFT 8
+#define USB_TRANS_CTR 0x0000
+#define USB_TRANS_INT 0x0100
+#define USB_TRANS_BULK 0x0200
+#define USB_TRANS_ISO 0x0300
+
+#define USB_EP_MF 0x0020
+#define USB_EP_RTE 0x0010
+
+#define USB_THS_SHIFT 2
+#define USB_THS_MASK 0x000c
+#define USB_THS_NORMAL 0x0
+#define USB_THS_IGNORE_IN 0x0004
+#define USB_THS_NACK 0x0008
+#define USB_THS_STALL 0x000c
+
+#define USB_RHS_SHIFT 0
+#define USB_RHS_MASK 0x0003
+#define USB_RHS_NORMAL 0x0
+#define USB_RHS_IGNORE_OUT 0x0001
+#define USB_RHS_NACK 0x0002
+#define USB_RHS_STALL 0x0003
+
+#define USB_RTHS_MASK 0x000f
+
+/* USB Command Register define */
+#define USB_CMD_STR_FIFO 0x80
+#define USB_CMD_FLUSH_FIFO 0x40
+#define USB_CMD_ISFT 0x20
+#define USB_CMD_DSFT 0x10
+#define USB_CMD_EP_MASK 0x03
+
+/* USB Event and Mask Register define */
+#define USB_E_MSF_MASK 0x0800
+#define USB_E_SFT_MASK 0x0400
+#define USB_E_RESET_MASK 0x0200
+#define USB_E_IDLE_MASK 0x0100
+#define USB_E_TXE4_MASK 0x0080
+#define USB_E_TXE3_MASK 0x0040
+#define USB_E_TXE2_MASK 0x0020
+#define USB_E_TXE1_MASK 0x0010
+#define USB_E_SOF_MASK 0x0008
+#define USB_E_BSY_MASK 0x0004
+#define USB_E_TXB_MASK 0x0002
+#define USB_E_RXB_MASK 0x0001
+#define USBER_ALL_CLEAR 0x0fff
+
+#define USB_E_DEFAULT_DEVICE (USB_E_RESET_MASK | USB_E_TXE4_MASK | \
+ USB_E_TXE3_MASK | USB_E_TXE2_MASK | \
+ USB_E_TXE1_MASK | USB_E_BSY_MASK | \
+ USB_E_TXB_MASK | USB_E_RXB_MASK)
+
+#define USB_E_TXE_MASK (USB_E_TXE4_MASK | USB_E_TXE3_MASK|\
+ USB_E_TXE2_MASK | USB_E_TXE1_MASK)
+/* USB Status Register define */
+#define USB_IDLE_STATUS_MASK 0x01
+
+/* USB Start of Frame Timer */
+#define USB_USSFT_MASK 0x3FFF
+
+/* USB Frame Number Register */
+#define USB_USFRN_MASK 0xFFFF
+
+struct usb_device_para{
+ u16 epptr[4];
+ u32 rstate;
+ u32 rptr;
+ u16 frame_n;
+ u16 rbcnt;
+ u32 rtemp;
+ u32 rxusb_data;
+ u16 rxuptr;
+ u8 reso[2];
+ u32 softbl;
+ u8 sofucrctemp;
+};
+
+struct usb_ep_para{
+ u16 rbase;
+ u16 tbase;
+ u8 rbmr;
+ u8 tbmr;
+ u16 mrblr;
+ u16 rbptr;
+ u16 tbptr;
+ u32 tstate;
+ u32 tptr;
+ u16 tcrc;
+ u16 tbcnt;
+ u32 ttemp;
+ u16 txusbu_ptr;
+ u8 reserve[2];
+};
+
+#define USB_BUSMODE_GBL 0x20
+#define USB_BUSMODE_BO_MASK 0x18
+#define USB_BUSMODE_BO_SHIFT 0x3
+#define USB_BUSMODE_BE 0x2
+#define USB_BUSMODE_CETM 0x04
+#define USB_BUSMODE_DTB 0x02
+
+/* Endpoint basic handle */
+#define ep_index(EP) ((EP)->desc->bEndpointAddress & 0xF)
+#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
+#define ep_is_in(EP) ((ep_index(EP) == 0) ? (EP->udc->ep0_dir == \
+ USB_DIR_IN) : ((EP)->desc->bEndpointAddress \
+ & USB_DIR_IN) == USB_DIR_IN)
+
+/* ep0 transfer state */
+#define WAIT_FOR_SETUP 0
+#define DATA_STATE_XMIT 1
+#define DATA_STATE_NEED_ZLP 2
+#define WAIT_FOR_OUT_STATUS 3
+#define DATA_STATE_RECV 4
+
+/* ep tramsfer mode */
+#define USBP_TM_CTL 0
+#define USBP_TM_ISO 1
+#define USBP_TM_BULK 2
+#define USBP_TM_INT 3
+
+/*-----------------------------------------------------------------------------
+ USB RX And TX DATA Frame
+ -----------------------------------------------------------------------------*/
+struct qe_frame{
+ u8 *data;
+ u32 len;
+ u32 status;
+ u32 info;
+
+ void *privdata;
+ struct list_head node;
+};
+
+/* Frame structure, info field. */
+#define PID_DATA0 0x80000000 /* Data toggle zero */
+#define PID_DATA1 0x40000000 /* Data toggle one */
+#define PID_SETUP 0x20000000 /* setup bit */
+#define SETUP_STATUS 0x10000000 /* setup status bit */
+#define SETADDR_STATUS 0x08000000 /* setupup address status bit */
+#define NO_REQ 0x04000000 /* Frame without request */
+#define HOST_DATA 0x02000000 /* Host data frame */
+#define FIRST_PACKET_IN_FRAME 0x01000000 /* first packet in the frame */
+#define TOKEN_FRAME 0x00800000 /* Host token frame */
+#define ZLP 0x00400000 /* Zero length packet */
+#define IN_TOKEN_FRAME 0x00200000 /* In token package */
+#define OUT_TOKEN_FRAME 0x00100000 /* Out token package */
+#define SETUP_TOKEN_FRAME 0x00080000 /* Setup token package */
+#define STALL_FRAME 0x00040000 /* Stall handshake */
+#define NACK_FRAME 0x00020000 /* Nack handshake */
+#define NO_PID 0x00010000 /* No send PID */
+#define NO_CRC 0x00008000 /* No send CRC */
+#define HOST_COMMAND 0x00004000 /* Host command frame */
+
+/* Frame status field */
+/* Receive side */
+#define FRAME_OK 0x00000000 /* Frame tranmitted or received OK */
+#define FRAME_ERROR 0x80000000 /* Error occured on frame */
+#define START_FRAME_LOST 0x40000000 /* START_FRAME_LOST */
+#define END_FRAME_LOST 0x20000000 /* END_FRAME_LOST */
+#define RX_ER_NONOCT 0x10000000 /* Rx Non Octet Aligned Packet */
+#define RX_ER_BITSTUFF 0x08000000 /* Frame Aborted --Received packet
+ with bit stuff error */
+#define RX_ER_CRC 0x04000000 /* Received packet with CRC error */
+#define RX_ER_OVERUN 0x02000000 /* Over-run occured on reception */
+#define RX_ER_PID 0x01000000 /* Wrong PID received */
+/* Tranmit side */
+#define TX_ER_NAK 0x00800000 /* Received NAK handshake */
+#define TX_ER_STALL 0x00400000 /* Received STALL handshake */
+#define TX_ER_TIMEOUT 0x00200000 /* Transmit time out */
+#define TX_ER_UNDERUN 0x00100000 /* Transmit underrun */
+#define FRAME_INPROGRESS 0x00080000 /* Frame is being transmitted */
+#define ER_DATA_UNDERUN 0x00040000 /* Frame is shorter then expected */
+#define ER_DATA_OVERUN 0x00020000 /* Frame is longer then expected */
+
+/* QE USB frame operation functions */
+#define frame_get_length(frm) (frm->len)
+#define frame_set_length(frm, leng) (frm->len = leng)
+#define frame_get_data(frm) (frm->data)
+#define frame_set_data(frm, dat) (frm->data = dat)
+#define frame_get_info(frm) (frm->info)
+#define frame_set_info(frm, inf) (frm->info = inf)
+#define frame_get_status(frm) (frm->status)
+#define frame_set_status(frm, stat) (frm->status = stat)
+#define frame_get_privdata(frm) (frm->privdata)
+#define frame_set_privdata(frm, dat) (frm->privdata = dat)
+
+static inline void qe_frame_clean(struct qe_frame *frm)
+{
+ frame_set_data(frm, NULL);
+ frame_set_length(frm, 0);
+ frame_set_status(frm, FRAME_OK);
+ frame_set_info(frm, 0);
+ frame_set_privdata(frm, NULL);
+}
+
+static inline void qe_frame_init(struct qe_frame *frm)
+{
+ qe_frame_clean(frm);
+ INIT_LIST_HEAD(&(frm->node));
+}
+
+struct qe_req {
+ struct usb_request req;
+ struct list_head queue;
+ /* ep_queue() func will add
+ a request->queue into a udc_ep->queue 'd tail */
+ struct qe_ep *ep;
+ unsigned mapped:1;
+};
+
+struct qe_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct qe_udc *udc;
+ const struct usb_endpoint_descriptor *desc;
+ struct usb_gadget *gadget;
+
+ u8 state;
+
+ struct qe_bd __iomem *rxbase;
+ struct qe_bd __iomem *n_rxbd;
+ struct qe_bd __iomem *e_rxbd;
+
+ struct qe_bd __iomem *txbase;
+ struct qe_bd __iomem *n_txbd;
+ struct qe_bd __iomem *c_txbd;
+
+ struct qe_frame *rxframe;
+ u8 *rxbuffer;
+ dma_addr_t rxbuf_d;
+ u8 rxbufmap;
+ unsigned char localnack;
+ int has_data;
+
+ struct qe_frame *txframe;
+ struct qe_req *tx_req;
+ int sent; /*data already sent */
+ int last; /*data sent in the last time*/
+
+ u8 dir;
+ u8 epnum;
+ u8 tm; /* transfer mode */
+ u8 data01;
+ u8 init;
+
+ u8 already_seen;
+ u8 enable_tasklet;
+ u8 setup_stage;
+ u32 last_io; /* timestamp */
+
+ char name[14];
+
+ unsigned double_buf:1;
+ unsigned stopped:1;
+ unsigned fnf:1;
+ unsigned has_dma:1;
+
+ u8 ackwait;
+ u8 dma_channel;
+ u16 dma_counter;
+ int lch;
+
+ struct timer_list timer;
+};
+
+struct qe_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct device *dev;
+ struct qe_ep eps[USB_MAX_ENDPOINTS];
+ struct usb_ctrlrequest local_setup_buff;
+ spinlock_t lock; /* lock for set/config qe_udc */
+ unsigned long soc_type; /* QE or CPM soc */
+
+ struct qe_req *status_req; /* ep0 status request */
+
+ /* USB and EP Parameter Block pointer */
+ struct usb_device_para __iomem *usb_param;
+ struct usb_ep_para __iomem *ep_param[4];
+
+ u32 max_pipes; /* Device max pipes */
+ u32 max_use_endpts; /* Max endpointes to be used */
+ u32 bus_reset; /* Device is bus reseting */
+ u32 resume_state; /* USB state to resume*/
+ u32 usb_state; /* USB current state */
+ u32 usb_next_state; /* USB next state */
+ u32 ep0_state; /* Enpoint zero state */
+ u32 ep0_dir; /* Enpoint zero direction: can be
+ USB_DIR_IN or USB_DIR_OUT*/
+ u32 usb_sof_count; /* SOF count */
+ u32 errors; /* USB ERRORs count */
+
+ u8 *tmpbuf;
+ u32 c_start;
+ u32 c_end;
+
+ u8 *nullbuf;
+ u8 *statusbuf;
+ dma_addr_t nullp;
+ u8 nullmap;
+ u8 device_address; /* Device USB address */
+
+ unsigned int usb_clock;
+ unsigned int usb_irq;
+ struct usb_ctlr __iomem *usb_regs;
+
+ struct tasklet_struct rx_tasklet;
+
+ struct completion *done; /* to make sure release() is done */
+};
+
+#define EP_STATE_IDLE 0
+#define EP_STATE_NACK 1
+#define EP_STATE_STALL 2
+
+/*
+ * transmit BD's status
+ */
+#define T_R 0x80000000 /* ready bit */
+#define T_W 0x20000000 /* wrap bit */
+#define T_I 0x10000000 /* interrupt on completion */
+#define T_L 0x08000000 /* last */
+#define T_TC 0x04000000 /* transmit CRC */
+#define T_CNF 0x02000000 /* wait for transmit confirm */
+#define T_LSP 0x01000000 /* Low-speed transaction */
+#define T_PID 0x00c00000 /* packet id */
+#define T_NAK 0x00100000 /* No ack. */
+#define T_STAL 0x00080000 /* Stall recieved */
+#define T_TO 0x00040000 /* time out */
+#define T_UN 0x00020000 /* underrun */
+
+#define DEVICE_T_ERROR (T_UN | T_TO)
+#define HOST_T_ERROR (T_UN | T_TO | T_NAK | T_STAL)
+#define DEVICE_T_BD_MASK DEVICE_T_ERROR
+#define HOST_T_BD_MASK HOST_T_ERROR
+
+#define T_PID_SHIFT 6
+#define T_PID_DATA0 0x00800000 /* Data 0 toggle */
+#define T_PID_DATA1 0x00c00000 /* Data 1 toggle */
+
+/*
+ * receive BD's status
+ */
+#define R_E 0x80000000 /* buffer empty */
+#define R_W 0x20000000 /* wrap bit */
+#define R_I 0x10000000 /* interrupt on reception */
+#define R_L 0x08000000 /* last */
+#define R_F 0x04000000 /* first */
+#define R_PID 0x00c00000 /* packet id */
+#define R_NO 0x00100000 /* Rx Non Octet Aligned Packet */
+#define R_AB 0x00080000 /* Frame Aborted */
+#define R_CR 0x00040000 /* CRC Error */
+#define R_OV 0x00020000 /* Overrun */
+
+#define R_ERROR (R_NO | R_AB | R_CR | R_OV)
+#define R_BD_MASK R_ERROR
+
+#define R_PID_DATA0 0x00000000
+#define R_PID_DATA1 0x00400000
+#define R_PID_SETUP 0x00800000
+
+#define CPM_USB_STOP_TX 0x2e600000
+#define CPM_USB_RESTART_TX 0x2e600000
+#define CPM_USB_STOP_TX_OPCODE 0x0a
+#define CPM_USB_RESTART_TX_OPCODE 0x0b
+#define CPM_USB_EP_SHIFT 5
+
+#ifndef CONFIG_CPM
+inline int cpm_command(u32 command, u8 opcode)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
+#ifndef CONFIG_QUICC_ENGINE
+inline int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol,
+ u32 cmd_input)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
+#endif /* __FSL_QE_UDC_H */
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 45ad556169f..091bb55c9aa 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -23,11 +23,8 @@
#include <linux/ioport.h>
#include <linux/types.h>
#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
@@ -44,11 +41,9 @@
#include <asm/byteorder.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/dma.h>
-#include <asm/cacheflush.h>
#include "fsl_usb2_udc.h"
@@ -61,8 +56,8 @@
static const char driver_name[] = "fsl-usb2-udc";
static const char driver_desc[] = DRIVER_DESC;
-volatile static struct usb_dr_device *dr_regs = NULL;
-volatile static struct usb_sys_interface *usb_sys_regs = NULL;
+static struct usb_dr_device *dr_regs;
+static struct usb_sys_interface *usb_sys_regs;
/* it is initialized in probe() */
static struct fsl_udc *udc_controller = NULL;
@@ -76,16 +71,14 @@ fsl_ep0_desc = {
.wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
};
-static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state);
-static int fsl_udc_resume(struct platform_device *pdev);
static void fsl_ep_fifo_flush(struct usb_ep *_ep);
#ifdef CONFIG_PPC32
#define fsl_readl(addr) in_le32(addr)
-#define fsl_writel(addr, val32) out_le32(val32, addr)
+#define fsl_writel(val32, addr) out_le32(addr, val32)
#else
#define fsl_readl(addr) readl(addr)
-#define fsl_writel(addr, val32) writel(addr, val32)
+#define fsl_writel(val32, addr) writel(val32, addr)
#endif
/********************************************************************
@@ -185,10 +178,6 @@ static int dr_controller_setup(struct fsl_udc *udc)
unsigned long timeout;
#define FSL_UDC_RESET_TIMEOUT 1000
- /* before here, make sure dr_regs has been initialized */
- if (!udc)
- return -EINVAL;
-
/* Stop and reset the usb controller */
tmp = fsl_readl(&dr_regs->usbcmd);
tmp &= ~USB_CMD_RUN_STOP;
@@ -202,7 +191,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
timeout = jiffies + FSL_UDC_RESET_TIMEOUT;
while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) {
if (time_after(jiffies, timeout)) {
- ERR("udc reset timeout! \n");
+ ERR("udc reset timeout!\n");
return -ETIMEDOUT;
}
cpu_relax();
@@ -315,7 +304,8 @@ static void dr_controller_stop(struct fsl_udc *udc)
return;
}
-void dr_ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type)
+static void dr_ep_setup(unsigned char ep_num, unsigned char dir,
+ unsigned char ep_type)
{
unsigned int tmp_epctrl = 0;
@@ -563,7 +553,7 @@ static int fsl_ep_disable(struct usb_ep *_ep)
/* nuke all pending requests (does flush) */
nuke(ep, -ESHUTDOWN);
- ep->desc = 0;
+ ep->desc = NULL;
ep->stopped = 1;
spin_unlock_irqrestore(&udc->lock, flags);
@@ -602,7 +592,7 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
}
/*-------------------------------------------------------------------------*/
-static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
+static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
{
int i = ep_index(ep) * 2 + ep_is_in(ep);
u32 temp, bitmask, tmp_stat;
@@ -653,13 +643,16 @@ static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
| EP_QUEUE_HEAD_STATUS_HALT));
dQH->size_ioc_int_sts &= temp;
+ /* Ensure that updates to the QH will occure before priming. */
+ wmb();
+
/* Prime endpoint by writing 1 to ENDPTPRIME */
temp = ep_is_in(ep)
? (1 << (ep_index(ep) + 16))
: (1 << (ep_index(ep)));
fsl_writel(temp, &dr_regs->endpointprime);
out:
- return 0;
+ return;
}
/* Fill in the dTD structure
@@ -710,7 +703,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
*is_last = 0;
if ((*is_last) == 0)
- VDBG("multi-dtd request!\n");
+ VDBG("multi-dtd request!");
/* Fill in the transfer size; set active bit */
swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
@@ -773,11 +766,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* catch various bogus parameters */
if (!_req || !req->req.complete || !req->req.buf
|| !list_empty(&req->queue)) {
- VDBG("%s, bad params\n", __func__);
+ VDBG("%s, bad params", __func__);
return -EINVAL;
}
if (unlikely(!_ep || !ep->desc)) {
- VDBG("%s, bad ep\n", __func__);
+ VDBG("%s, bad ep", __func__);
return -EINVAL;
}
if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
@@ -1069,7 +1062,7 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
udc = container_of(gadget, struct fsl_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
- VDBG("VBUS %s\n", is_active ? "on" : "off");
+ VDBG("VBUS %s", is_active ? "on" : "off");
udc->vbus_active = (is_active != 0);
if (can_pullup(udc))
fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
@@ -1146,7 +1139,6 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
{
struct fsl_req *req = udc->status_req;
struct fsl_ep *ep;
- int status = 0;
if (direction == EP_DIR_IN)
udc->ep0_dir = USB_DIR_IN;
@@ -1164,27 +1156,21 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
req->dtd_count = 0;
if (fsl_req_to_dtd(req) == 0)
- status = fsl_queue_td(ep, req);
+ fsl_queue_td(ep, req);
else
return -ENOMEM;
- if (status)
- ERR("Can't queue ep0 status request \n");
list_add_tail(&req->queue, &ep->queue);
- return status;
+ return 0;
}
-static inline int udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe)
+static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe)
{
struct fsl_ep *ep = get_ep_by_pipe(udc, pipe);
- if (!ep->name)
- return 0;
-
- nuke(ep, -ESHUTDOWN);
-
- return 0;
+ if (ep->name)
+ nuke(ep, -ESHUTDOWN);
}
/*
@@ -1208,10 +1194,8 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
u16 index, u16 length)
{
u16 tmp = 0; /* Status, cpu endian */
-
struct fsl_req *req;
struct fsl_ep *ep;
- int status = 0;
ep = &udc->eps[0];
@@ -1250,14 +1234,10 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
/* prime the data phase */
if ((fsl_req_to_dtd(req) == 0))
- status = fsl_queue_td(ep, req);
+ fsl_queue_td(ep, req);
else /* no mem */
goto stall;
- if (status) {
- ERR("Can't respond to getstatus request \n");
- goto stall;
- }
list_add_tail(&req->queue, &ep->queue);
udc->ep0_state = DATA_STATE_XMIT;
return;
@@ -1397,7 +1377,7 @@ static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0,
udc->ep0_state = WAIT_FOR_SETUP;
break;
case WAIT_FOR_SETUP:
- ERR("Unexpect ep0 packets \n");
+ ERR("Unexpect ep0 packets\n");
break;
default:
ep0stall(udc);
@@ -1476,7 +1456,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
status = -EILSEQ;
break;
} else
- ERR("Unknown error has occured (0x%x)!\r\n",
+ ERR("Unknown error has occured (0x%x)!\n",
errors);
} else if (le32_to_cpu(curr_td->size_ioc_sts)
@@ -1495,7 +1475,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
}
} else {
td_complete++;
- VDBG("dTD transmitted successful ");
+ VDBG("dTD transmitted successful");
}
if (j != curr_req->dtd_count - 1)
@@ -1568,9 +1548,6 @@ static void port_change_irq(struct fsl_udc *udc)
{
u32 speed;
- if (udc->bus_reset)
- udc->bus_reset = 0;
-
/* Bus resetting is finished */
if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
/* Get the speed */
@@ -1678,8 +1655,6 @@ static void reset_irq(struct fsl_udc *udc)
if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
VDBG("Bus reset");
- /* Bus is reseting */
- udc->bus_reset = 1;
/* Reset all the queues, include XD, dTD, EP queue
* head and TR Queue */
reset_queues(udc);
@@ -1768,7 +1743,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
}
if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
- VDBG("Error IRQ %x ", irq_src);
+ VDBG("Error IRQ %x", irq_src);
}
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1799,7 +1774,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
/* lock is needed but whether should use this lock or another */
spin_lock_irqsave(&udc_controller->lock, flags);
- driver->driver.bus = 0;
+ driver->driver.bus = NULL;
/* hook up the driver */
udc_controller->driver = driver;
udc_controller->gadget.dev.driver = &driver->driver;
@@ -1809,8 +1784,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
retval = driver->bind(&udc_controller->gadget);
if (retval) {
VDBG("bind to %s --> %d", driver->driver.name, retval);
- udc_controller->gadget.dev.driver = 0;
- udc_controller->driver = 0;
+ udc_controller->gadget.dev.driver = NULL;
+ udc_controller->driver = NULL;
goto out;
}
@@ -1819,12 +1794,12 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_state = WAIT_FOR_SETUP;
udc_controller->ep0_dir = 0;
- printk(KERN_INFO "%s: bind to driver %s \n",
+ printk(KERN_INFO "%s: bind to driver %s\n",
udc_controller->gadget.name, driver->driver.name);
out:
if (retval)
- printk("retval %d \n", retval);
+ printk("gadget driver register failed %d\n", retval);
return retval;
}
EXPORT_SYMBOL(usb_gadget_register_driver);
@@ -1842,7 +1817,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
return -EINVAL;
if (udc_controller->transceiver)
- (void)otg_set_peripheral(udc_controller->transceiver, 0);
+ otg_set_peripheral(udc_controller->transceiver, NULL);
/* stop DR, disable intr */
dr_controller_stop(udc_controller);
@@ -1863,10 +1838,10 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
/* unbind gadget and unhook driver. */
driver->unbind(&udc_controller->gadget);
- udc_controller->gadget.dev.driver = 0;
- udc_controller->driver = 0;
+ udc_controller->gadget.dev.driver = NULL;
+ udc_controller->driver = NULL;
- printk("unregistered gadget driver '%s'\r\n", driver->driver.name);
+ printk("unregistered gadget driver '%s'\n", driver->driver.name);
return 0;
}
EXPORT_SYMBOL(usb_gadget_unregister_driver);
@@ -1922,7 +1897,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
tmp_reg = fsl_readl(&dr_regs->usbsts);
t = scnprintf(next, size,
"USB Status Reg:\n"
- "Dr Suspend: %d" "Reset Received: %d" "System Error: %s"
+ "Dr Suspend: %d Reset Received: %d System Error: %s "
"USB Error Interrupt: %s\n\n",
(tmp_reg & USB_STS_SUSPEND) ? 1 : 0,
(tmp_reg & USB_STS_RESET) ? 1 : 0,
@@ -1934,11 +1909,11 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
tmp_reg = fsl_readl(&dr_regs->usbintr);
t = scnprintf(next, size,
"USB Intrrupt Enable Reg:\n"
- "Sleep Enable: %d" "SOF Received Enable: %d"
+ "Sleep Enable: %d SOF Received Enable: %d "
"Reset Enable: %d\n"
- "System Error Enable: %d"
+ "System Error Enable: %d "
"Port Change Dectected Enable: %d\n"
- "USB Error Intr Enable: %d" "USB Intr Enable: %d\n\n",
+ "USB Error Intr Enable: %d USB Intr Enable: %d\n\n",
(tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0,
(tmp_reg & USB_INTR_SOF_EN) ? 1 : 0,
(tmp_reg & USB_INTR_RESET_EN) ? 1 : 0,
@@ -1951,21 +1926,21 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
tmp_reg = fsl_readl(&dr_regs->frindex);
t = scnprintf(next, size,
- "USB Frame Index Reg:" "Frame Number is 0x%x\n\n",
+ "USB Frame Index Reg: Frame Number is 0x%x\n\n",
(tmp_reg & USB_FRINDEX_MASKS));
size -= t;
next += t;
tmp_reg = fsl_readl(&dr_regs->deviceaddr);
t = scnprintf(next, size,
- "USB Device Address Reg:" "Device Addr is 0x%x\n\n",
+ "USB Device Address Reg: Device Addr is 0x%x\n\n",
(tmp_reg & USB_DEVICE_ADDRESS_MASK));
size -= t;
next += t;
tmp_reg = fsl_readl(&dr_regs->endpointlistaddr);
t = scnprintf(next, size,
- "USB Endpoint List Address Reg:"
+ "USB Endpoint List Address Reg: "
"Device Addr is 0x%x\n\n",
(tmp_reg & USB_EP_LIST_ADDRESS_MASK));
size -= t;
@@ -1974,11 +1949,12 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
tmp_reg = fsl_readl(&dr_regs->portsc1);
t = scnprintf(next, size,
"USB Port Status&Control Reg:\n"
- "Port Transceiver Type : %s" "Port Speed: %s \n"
- "PHY Low Power Suspend: %s" "Port Reset: %s"
- "Port Suspend Mode: %s \n" "Over-current Change: %s"
+ "Port Transceiver Type : %s Port Speed: %s\n"
+ "PHY Low Power Suspend: %s Port Reset: %s "
+ "Port Suspend Mode: %s\n"
+ "Over-current Change: %s "
"Port Enable/Disable Change: %s\n"
- "Port Enabled/Disabled: %s"
+ "Port Enabled/Disabled: %s "
"Current Connect Status: %s\n\n", ( {
char *s;
switch (tmp_reg & PORTSCX_PTS_FSLS) {
@@ -2023,7 +1999,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
tmp_reg = fsl_readl(&dr_regs->usbmode);
t = scnprintf(next, size,
- "USB Mode Reg:" "Controller Mode is : %s\n\n", ( {
+ "USB Mode Reg: Controller Mode is: %s\n\n", ( {
char *s;
switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) {
case USB_MODE_CTRL_MODE_IDLE:
@@ -2042,7 +2018,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
tmp_reg = fsl_readl(&dr_regs->endptsetupstat);
t = scnprintf(next, size,
- "Endpoint Setup Status Reg:" "SETUP on ep 0x%x\n\n",
+ "Endpoint Setup Status Reg: SETUP on ep 0x%x\n\n",
(tmp_reg & EP_SETUP_STATUS_MASK));
size -= t;
next += t;
@@ -2055,12 +2031,12 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
next += t;
}
tmp_reg = fsl_readl(&dr_regs->endpointprime);
- t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n", tmp_reg);
+ t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n\n", tmp_reg);
size -= t;
next += t;
tmp_reg = usb_sys_regs->snoop1;
- t = scnprintf(next, size, "\nSnoop1 Reg : = [0x%x]\n\n", tmp_reg);
+ t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
size -= t;
next += t;
@@ -2084,7 +2060,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
} else {
list_for_each_entry(req, &ep->queue, queue) {
t = scnprintf(next, size,
- "req %p actual 0x%x length 0x%x buf %p\n",
+ "req %p actual 0x%x length 0x%x buf %p\n",
&req->req, req->req.actual,
req->req.length, req->req.buf);
size -= t;
@@ -2110,7 +2086,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
} else {
list_for_each_entry(req, &ep->queue, queue) {
t = scnprintf(next, size,
- "req %p actual 0x%x length"
+ "req %p actual 0x%x length "
"0x%x buf %p\n",
&req->req, req->req.actual,
req->req.length, req->req.buf);
@@ -2202,7 +2178,6 @@ static int __init struct_udc_setup(struct fsl_udc *udc,
udc->usb_state = USB_STATE_POWERED;
udc->ep0_dir = 0;
udc->remote_wakeup = 0; /* default to 0 on reset */
- spin_lock_init(&udc->lock);
return 0;
}
@@ -2254,7 +2229,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
u32 dccparams;
if (strcmp(pdev->name, driver_name)) {
- VDBG("Wrong device\n");
+ VDBG("Wrong device");
return -ENODEV;
}
@@ -2264,23 +2239,26 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ spin_lock_init(&udc_controller->lock);
+ udc_controller->stopped = 1;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- kfree(udc_controller);
- return -ENXIO;
+ ret = -ENXIO;
+ goto err_kfree;
}
if (!request_mem_region(res->start, res->end - res->start + 1,
driver_name)) {
- ERR("request mem region for %s failed \n", pdev->name);
- kfree(udc_controller);
- return -EBUSY;
+ ERR("request mem region for %s failed\n", pdev->name);
+ ret = -EBUSY;
+ goto err_kfree;
}
dr_regs = ioremap(res->start, res->end - res->start + 1);
if (!dr_regs) {
ret = -ENOMEM;
- goto err1;
+ goto err_release_mem_region;
}
usb_sys_regs = (struct usb_sys_interface *)
@@ -2291,7 +2269,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
if (!(dccparams & DCCPARAMS_DC)) {
ERR("This SOC doesn't support device role\n");
ret = -ENODEV;
- goto err2;
+ goto err_iounmap;
}
/* Get max device endpoints */
/* DEN is bidirectional ep number, max_ep doubles the number */
@@ -2300,22 +2278,22 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
udc_controller->irq = platform_get_irq(pdev, 0);
if (!udc_controller->irq) {
ret = -ENODEV;
- goto err2;
+ goto err_iounmap;
}
ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
driver_name, udc_controller);
if (ret != 0) {
- ERR("cannot request irq %d err %d \n",
+ ERR("cannot request irq %d err %d\n",
udc_controller->irq, ret);
- goto err2;
+ goto err_iounmap;
}
/* Initialize the udc structure including QH member and other member */
if (struct_udc_setup(udc_controller, pdev)) {
ERR("Can't initialize udc data structure\n");
ret = -ENOMEM;
- goto err3;
+ goto err_free_irq;
}
/* initialize usb hw reg except for regs for EP,
@@ -2336,7 +2314,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
udc_controller->gadget.dev.parent = &pdev->dev;
ret = device_register(&udc_controller->gadget.dev);
if (ret < 0)
- goto err3;
+ goto err_free_irq;
/* setup QH and epctrl for ep0 */
ep0_setup(udc_controller);
@@ -2366,20 +2344,22 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
if (udc_controller->td_pool == NULL) {
ret = -ENOMEM;
- goto err4;
+ goto err_unregister;
}
create_proc_file();
return 0;
-err4:
+err_unregister:
device_unregister(&udc_controller->gadget.dev);
-err3:
+err_free_irq:
free_irq(udc_controller->irq, udc_controller);
-err2:
+err_iounmap:
iounmap(dr_regs);
-err1:
+err_release_mem_region:
release_mem_region(res->start, res->end - res->start + 1);
+err_kfree:
kfree(udc_controller);
+ udc_controller = NULL;
return ret;
}
@@ -2469,7 +2449,7 @@ module_init(udc_init);
static void __exit udc_exit(void)
{
platform_driver_unregister(&udc_driver);
- printk("%s unregistered \n", driver_desc);
+ printk("%s unregistered\n", driver_desc);
}
module_exit(udc_exit);
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index 6131752a38b..e63ef12645f 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -424,16 +424,6 @@ struct ep_td_struct {
/* Controller dma boundary */
#define UDC_DMA_BOUNDARY 0x1000
-/* -----------------------------------------------------------------------*/
-/* ##### enum data
-*/
-typedef enum {
- e_ULPI,
- e_UTMI_8BIT,
- e_UTMI_16BIT,
- e_SERIAL
-} e_PhyInterface;
-
/*-------------------------------------------------------------------------*/
/* ### driver private data
@@ -469,9 +459,9 @@ struct fsl_ep {
#define EP_DIR_OUT 0
struct fsl_udc {
-
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
+ struct completion *done; /* to make sure release() is done */
struct fsl_ep *eps;
unsigned int max_ep;
unsigned int irq;
@@ -492,20 +482,13 @@ struct fsl_udc {
size_t ep_qh_size; /* size after alignment adjustment*/
dma_addr_t ep_qh_dma; /* dma address of QH */
- u32 max_pipes; /* Device max pipes */
- u32 max_use_endpts; /* Max endpointes to be used */
- u32 bus_reset; /* Device is bus reseting */
+ u32 max_pipes; /* Device max pipes */
u32 resume_state; /* USB state to resume */
u32 usb_state; /* USB current state */
- u32 usb_next_state; /* USB next state */
u32 ep0_state; /* Endpoint zero state */
u32 ep0_dir; /* Endpoint zero direction: can be
USB_DIR_IN or USB_DIR_OUT */
- u32 usb_sof_count; /* SOF count */
- u32 errors; /* USB ERRORs count */
u8 device_address; /* Device USB address */
-
- struct completion *done; /* to make sure release() is done */
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 17d9905101b..4e3107dd2f3 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -151,6 +151,13 @@
#define gadget_is_m66592(g) 0
#endif
+/* Freescale CPM/QE UDC SUPPORT */
+#ifdef CONFIG_USB_GADGET_FSL_QE
+#define gadget_is_fsl_qe(g) !strcmp("fsl_qe_udc", (g)->name)
+#else
+#define gadget_is_fsl_qe(g) 0
+#endif
+
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
@@ -216,6 +223,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x20;
else if (gadget_is_m66592(gadget))
return 0x21;
+ else if (gadget_is_fsl_qe(gadget))
+ return 0x22;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 6eee760410d..60d3f9e9b51 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -222,7 +222,7 @@ static struct usb_config_descriptor config_desc = {
* power properties of the device. Is it selfpowered?
*/
.bmAttributes = USB_CONFIG_ATT_ONE,
- .bMaxPower = 1,
+ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
};
/* B.3.1 Standard AC Interface Descriptor */
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 5cfb5ebf388..8ae70de2c37 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -178,6 +178,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
/* ep_reset() has already been called */
ep->stopped = 0;
+ ep->wedged = 0;
ep->out_overflow = 0;
/* set speed-dependent max packet; may kick in high bandwidth */
@@ -1218,7 +1219,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req)
static int net2280_fifo_status (struct usb_ep *_ep);
static int
-net2280_set_halt (struct usb_ep *_ep, int value)
+net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
{
struct net2280_ep *ep;
unsigned long flags;
@@ -1239,16 +1240,21 @@ net2280_set_halt (struct usb_ep *_ep, int value)
else if (ep->is_in && value && net2280_fifo_status (_ep) != 0)
retval = -EAGAIN;
else {
- VDEBUG (ep->dev, "%s %s halt\n", _ep->name,
- value ? "set" : "clear");
+ VDEBUG (ep->dev, "%s %s %s\n", _ep->name,
+ value ? "set" : "clear",
+ wedged ? "wedge" : "halt");
/* set/clear, then synch memory views with the device */
if (value) {
if (ep->num == 0)
ep->dev->protocol_stall = 1;
else
set_halt (ep);
- } else
+ if (wedged)
+ ep->wedged = 1;
+ } else {
clear_halt (ep);
+ ep->wedged = 0;
+ }
(void) readl (&ep->regs->ep_rsp);
}
spin_unlock_irqrestore (&ep->dev->lock, flags);
@@ -1257,6 +1263,20 @@ net2280_set_halt (struct usb_ep *_ep, int value)
}
static int
+net2280_set_halt(struct usb_ep *_ep, int value)
+{
+ return net2280_set_halt_and_wedge(_ep, value, 0);
+}
+
+static int
+net2280_set_wedge(struct usb_ep *_ep)
+{
+ if (!_ep || _ep->name == ep0name)
+ return -EINVAL;
+ return net2280_set_halt_and_wedge(_ep, 1, 1);
+}
+
+static int
net2280_fifo_status (struct usb_ep *_ep)
{
struct net2280_ep *ep;
@@ -1302,6 +1322,7 @@ static const struct usb_ep_ops net2280_ep_ops = {
.dequeue = net2280_dequeue,
.set_halt = net2280_set_halt,
+ .set_wedge = net2280_set_wedge,
.fifo_status = net2280_fifo_status,
.fifo_flush = net2280_fifo_flush,
};
@@ -2410,9 +2431,14 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
goto do_stall;
if ((e = get_ep_by_addr (dev, w_index)) == 0)
goto do_stall;
- clear_halt (e);
+ if (e->wedged) {
+ VDEBUG(dev, "%s wedged, halt not cleared\n",
+ ep->ep.name);
+ } else {
+ VDEBUG(dev, "%s clear halt\n", ep->ep.name);
+ clear_halt(e);
+ }
allow_status (ep);
- VDEBUG (dev, "%s clear halt\n", ep->ep.name);
goto next_endpoints;
}
break;
@@ -2427,6 +2453,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
goto do_stall;
if ((e = get_ep_by_addr (dev, w_index)) == 0)
goto do_stall;
+ if (e->ep.name == ep0name)
+ goto do_stall;
set_halt (e);
allow_status (ep);
VDEBUG (dev, "%s set halt\n", ep->ep.name);
diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h
index 81a71dbdc2c..c36852263d9 100644
--- a/drivers/usb/gadget/net2280.h
+++ b/drivers/usb/gadget/net2280.h
@@ -109,6 +109,7 @@ struct net2280_ep {
in_fifo_validate : 1,
out_overflow : 1,
stopped : 1,
+ wedged : 1,
is_in : 1,
is_iso : 1,
responded : 1;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index bb54cca4c54..34e9e393f92 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2313,6 +2313,13 @@ static int proc_otg_show(struct seq_file *s)
tmp = omap_readl(OTG_REV);
if (cpu_is_omap24xx()) {
+ /*
+ * REVISIT: Not clear how this works on OMAP2. trans
+ * is ANDed to produce bits 7 and 8, which might make
+ * sense for USB_TRANSCEIVER_CTRL on OMAP1,
+ * but with CONTROL_DEVCONF, these bits have something to
+ * do with the frame adjustment counter and McBSP2.
+ */
ctrl_name = "control_devconf";
trans = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
} else {
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 2b3b9e1dd2e..5a3034fdfe4 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -252,7 +252,7 @@ static struct usb_config_descriptor config_desc = {
.bConfigurationValue = DEV_CONFIG_VALUE,
.iConfiguration = 0,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1 /* Self-Powered */
+ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
};
static struct usb_interface_descriptor intf_desc = {
@@ -1278,8 +1278,7 @@ unknown:
/* respond with data transfer before status phase? */
if (value >= 0) {
req->length = value;
- req->zero = value < wLength
- && (value % gadget->ep0->maxpacket) == 0;
+ req->zero = value < wLength;
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
DBG(dev, "ep_queue --> %d\n", value);
@@ -1477,7 +1476,6 @@ autoconf_fail:
if (gadget->is_otg) {
otg_desc.bmAttributes |= USB_OTG_HNP,
config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
- config_desc.bMaxPower = 4;
}
spin_lock_init(&dev->lock);
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 7cbc78a6853..caa37c95802 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
@@ -651,7 +650,7 @@ pxa_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
struct pxa27x_request *req;
req = kzalloc(sizeof *req, gfp_flags);
- if (!req || !_ep)
+ if (!req)
return NULL;
INIT_LIST_HEAD(&req->queue);
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 29d13ebe750..00ba06b4475 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1651,7 +1651,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
return -EBUSY;
if (!driver->bind || !driver->setup
- || driver->speed != USB_SPEED_FULL) {
+ || driver->speed < USB_SPEED_FULL) {
printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
driver->bind, driver->setup, driver->speed);
return -EINVAL;
@@ -1894,11 +1894,8 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
udc->regs_info = debugfs_create_file("registers", S_IRUGO,
s3c2410_udc_debugfs_root,
udc, &s3c2410_udc_debugfs_fops);
- if (IS_ERR(udc->regs_info)) {
- dev_warn(dev, "debugfs file creation failed %ld\n",
- PTR_ERR(udc->regs_info));
- udc->regs_info = NULL;
- }
+ if (!udc->regs_info)
+ dev_warn(dev, "debugfs file creation failed\n");
}
dev_dbg(dev, "probe ok\n");
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 3faa7a7022d..37879af1c43 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -43,6 +43,7 @@
#include "epautoconf.c"
#include "f_acm.c"
+#include "f_obex.c"
#include "f_serial.c"
#include "u_serial.c"
@@ -56,6 +57,7 @@
#define GS_VENDOR_ID 0x0525 /* NetChip */
#define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */
#define GS_CDC_PRODUCT_ID 0xa4a7 /* ... as CDC-ACM */
+#define GS_CDC_OBEX_PRODUCT_ID 0xa4a9 /* ... as CDC-OBEX */
/* string IDs are assigned dynamically */
@@ -125,6 +127,10 @@ static int use_acm = true;
module_param(use_acm, bool, 0);
MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes");
+static int use_obex = false;
+module_param(use_obex, bool, 0);
+MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no");
+
static unsigned n_ports = 1;
module_param(n_ports, uint, 0);
MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
@@ -139,6 +145,8 @@ static int __init serial_bind_config(struct usb_configuration *c)
for (i = 0; i < n_ports && status == 0; i++) {
if (use_acm)
status = acm_bind_config(c, i);
+ else if (use_obex)
+ status = obex_bind_config(c, i);
else
status = gser_bind_config(c, i);
}
@@ -151,7 +159,6 @@ static struct usb_configuration serial_config_driver = {
/* .bConfigurationValue = f(use_acm) */
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1, /* 2 mA, minimal */
};
static int __init gs_bind(struct usb_composite_dev *cdev)
@@ -249,6 +256,12 @@ static int __init init(void)
device_desc.bDeviceClass = USB_CLASS_COMM;
device_desc.idProduct =
__constant_cpu_to_le16(GS_CDC_PRODUCT_ID);
+ } else if (use_obex) {
+ serial_config_driver.label = "CDC OBEX config";
+ serial_config_driver.bConfigurationValue = 3;
+ device_desc.bDeviceClass = USB_CLASS_COMM;
+ device_desc.idProduct =
+ __constant_cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
} else {
serial_config_driver.label = "Generic Serial config";
serial_config_driver.bConfigurationValue = 1;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index dbd575a194f..66948b72bb9 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -873,6 +873,13 @@ struct net_device *gether_connect(struct gether *link)
spin_lock(&dev->lock);
dev->port_usb = link;
link->ioport = dev;
+ if (netif_running(dev->net)) {
+ if (link->open)
+ link->open(link);
+ } else {
+ if (link->close)
+ link->close(link);
+ }
spin_unlock(&dev->lock);
netif_carrier_on(dev->net);
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
index af3910d01ae..300f0ed9475 100644
--- a/drivers/usb/gadget/u_serial.h
+++ b/drivers/usb/gadget/u_serial.h
@@ -62,5 +62,6 @@ void gserial_disconnect(struct gserial *);
/* functions are bound to configurations by a config or gadget driver */
int acm_bind_config(struct usb_configuration *c, u8 port_num);
int gser_bind_config(struct usb_configuration *c, u8 port_num);
+int obex_bind_config(struct usb_configuration *c, u8 port_num);
#endif /* __U_SERIAL_H */
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 228797e54f9..56f592dc0b3 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -138,7 +138,6 @@ config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
- select I2C if ARCH_PNX4008
---help---
The Open Host Controller Interface (OHCI) is a standard for accessing
USB 1.1 host controller hardware. It does more in hardware than Intel's
@@ -305,3 +304,31 @@ config SUPERH_ON_CHIP_R8A66597
help
This driver enables support for the on-chip R8A66597 in the
SH7366 and SH7723 processors.
+
+config USB_WHCI_HCD
+ tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on PCI && USB
+ select USB_WUSB
+ select UWB_WHCI
+ help
+ A driver for PCI-based Wireless USB Host Controllers that are
+ compliant with the WHCI specification.
+
+ To compile this driver a module, choose M here: the module
+ will be called "whci-hcd".
+
+config USB_HWA_HCD
+ tristate "Host Wire Adapter (HWA) driver (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on USB
+ select USB_WUSB
+ select UWB_HWA
+ help
+ This driver enables you to connect Wireless USB devices to
+ your system using a Host Wire Adaptor USB dongle. This is an
+ UWB Radio Controller and WUSB Host Controller connected to
+ your machine via USB (specified in WUSB1.0).
+
+ To compile this driver a module, choose M here: the module
+ will be called "hwa-hc".
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index f1edda2dcfd..23be2222404 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -8,6 +8,8 @@ endif
isp1760-objs := isp1760-hcd.o isp1760-if.o
+obj-$(CONFIG_USB_WHCI_HCD) += whci/
+
obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
@@ -19,3 +21,4 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
+obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index b0f8ed5a7fb..0cb53ca8d34 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -358,7 +358,8 @@ struct debug_buffer {
struct usb_bus *bus;
struct mutex mutex; /* protect filling of buffer */
size_t count; /* number of characters filled into buffer */
- char *page;
+ char *output_buf;
+ size_t alloc_size;
};
#define speed_char(info1) ({ char tmp; \
@@ -488,8 +489,8 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
hcd = bus_to_hcd(buf->bus);
ehci = hcd_to_ehci (hcd);
- next = buf->page;
- size = PAGE_SIZE;
+ next = buf->output_buf;
+ size = buf->alloc_size;
*next = 0;
@@ -510,7 +511,7 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
}
spin_unlock_irqrestore (&ehci->lock, flags);
- return strlen(buf->page);
+ return strlen(buf->output_buf);
}
#define DBG_SCHED_LIMIT 64
@@ -531,8 +532,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
hcd = bus_to_hcd(buf->bus);
ehci = hcd_to_ehci (hcd);
- next = buf->page;
- size = PAGE_SIZE;
+ next = buf->output_buf;
+ size = buf->alloc_size;
temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size);
size -= temp;
@@ -568,14 +569,16 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
for (temp = 0; temp < seen_count; temp++) {
if (seen [temp].ptr != p.ptr)
continue;
- if (p.qh->qh_next.ptr)
+ if (p.qh->qh_next.ptr) {
temp = scnprintf (next, size,
" ...");
- p.ptr = NULL;
+ size -= temp;
+ next += temp;
+ }
break;
}
/* show more info the first time around */
- if (temp == seen_count && p.ptr) {
+ if (temp == seen_count) {
u32 scratch = hc32_to_cpup(ehci,
&p.qh->hw_info1);
struct ehci_qtd *qtd;
@@ -649,7 +652,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
spin_unlock_irqrestore (&ehci->lock, flags);
kfree (seen);
- return PAGE_SIZE - size;
+ return buf->alloc_size - size;
}
#undef DBG_SCHED_LIMIT
@@ -665,14 +668,14 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
hcd = bus_to_hcd(buf->bus);
ehci = hcd_to_ehci (hcd);
- next = buf->page;
- size = PAGE_SIZE;
+ next = buf->output_buf;
+ size = buf->alloc_size;
spin_lock_irqsave (&ehci->lock, flags);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
size = scnprintf (next, size,
- "bus %s, device %s (driver " DRIVER_VERSION ")\n"
+ "bus %s, device %s\n"
"%s\n"
"SUSPENDED (no register access)\n",
hcd->self.controller->bus->name,
@@ -684,7 +687,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
/* Capability Registers */
i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
temp = scnprintf (next, size,
- "bus %s, device %s (driver " DRIVER_VERSION ")\n"
+ "bus %s, device %s\n"
"%s\n"
"EHCI %x.%02x, hcd state %d\n",
hcd->self.controller->bus->name,
@@ -808,7 +811,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
done:
spin_unlock_irqrestore (&ehci->lock, flags);
- return PAGE_SIZE - size;
+ return buf->alloc_size - size;
}
static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
@@ -822,6 +825,7 @@ static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
buf->bus = bus;
buf->fill_func = fill_func;
mutex_init(&buf->mutex);
+ buf->alloc_size = PAGE_SIZE;
}
return buf;
@@ -831,10 +835,10 @@ static int fill_buffer(struct debug_buffer *buf)
{
int ret = 0;
- if (!buf->page)
- buf->page = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!buf->output_buf)
+ buf->output_buf = (char *)vmalloc(buf->alloc_size);
- if (!buf->page) {
+ if (!buf->output_buf) {
ret = -ENOMEM;
goto out;
}
@@ -867,7 +871,7 @@ static ssize_t debug_output(struct file *file, char __user *user_buf,
mutex_unlock(&buf->mutex);
ret = simple_read_from_buffer(user_buf, len, offset,
- buf->page, buf->count);
+ buf->output_buf, buf->count);
out:
return ret;
@@ -879,8 +883,8 @@ static int debug_close(struct inode *inode, struct file *file)
struct debug_buffer *buf = file->private_data;
if (buf) {
- if (buf->page)
- free_page((unsigned long)buf->page);
+ if (buf->output_buf)
+ vfree(buf->output_buf);
kfree(buf);
}
@@ -895,10 +899,14 @@ static int debug_async_open(struct inode *inode, struct file *file)
static int debug_periodic_open(struct inode *inode, struct file *file)
{
- file->private_data = alloc_buffer(inode->i_private,
- fill_periodic_buffer);
+ struct debug_buffer *buf;
+ buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
+ if (!buf)
+ return -ENOMEM;
- return file->private_data ? 0 : -ENOMEM;
+ buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
+ file->private_data = buf;
+ return 0;
}
static int debug_registers_open(struct inode *inode, struct file *file)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 8409e0705d6..15a803b206b 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -24,6 +24,7 @@
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
@@ -59,7 +60,6 @@
* providing early devices for those host controllers to talk to!
*/
-#define DRIVER_VERSION "10 Dec 2004"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
@@ -620,9 +620,9 @@ static int ehci_run (struct usb_hcd *hcd)
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
- "USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
+ "USB %x.%x started, EHCI %x.%02x%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
- temp >> 8, temp & 0xff, DRIVER_VERSION,
+ temp >> 8, temp & 0xff,
ignore_oc ? ", overcurrent ignored" : "");
ehci_writel(ehci, INTR_MASK,
@@ -706,7 +706,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
pcd_status = status;
/* resume root hub? */
- if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
+ if (!(cmd & CMD_RUN))
usb_hcd_resume_root_hub(hcd);
while (i--) {
@@ -715,8 +715,11 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
if (pstatus & PORT_OWNER)
continue;
- if (!(pstatus & PORT_RESUME)
- || ehci->reset_done [i] != 0)
+ if (!(test_bit(i, &ehci->suspended_ports) &&
+ ((pstatus & PORT_RESUME) ||
+ !(pstatus & PORT_SUSPEND)) &&
+ (pstatus & PORT_PE) &&
+ ehci->reset_done[i] == 0))
continue;
/* start 20 msec resume signaling from this port,
@@ -731,9 +734,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
- dbg_cmd (ehci, "fatal", ehci_readl(ehci,
- &ehci->regs->command));
- dbg_status (ehci, "fatal", status);
+ dbg_cmd(ehci, "fatal", cmd);
+ dbg_status(ehci, "fatal", status);
if (status & STS_HALT) {
ehci_err (ehci, "fatal error\n");
dead:
@@ -994,9 +996,7 @@ static int ehci_get_frame (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
-#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
-
-MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_LICENSE ("GPL");
@@ -1020,11 +1020,6 @@ MODULE_LICENSE ("GPL");
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
#endif
-#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE)
-#include "ehci-ppc-soc.c"
-#define PLATFORM_DRIVER ehci_ppc_soc_driver
-#endif
-
#ifdef CONFIG_USB_EHCI_HCD_PPC_OF
#include "ehci-ppc-of.c"
#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver
@@ -1049,6 +1044,16 @@ static int __init ehci_hcd_init(void)
{
int retval = 0;
+ if (usb_disabled())
+ return -ENODEV;
+
+ printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);
+ set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+ if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
+ test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
+ printk(KERN_WARNING "Warning! ehci_hcd should always be loaded"
+ " before uhci_hcd and ohci_hcd, not after\n");
+
pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
hcd_name,
sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
@@ -1056,8 +1061,10 @@ static int __init ehci_hcd_init(void)
#ifdef DEBUG
ehci_debug_root = debugfs_create_dir("ehci", NULL);
- if (!ehci_debug_root)
- return -ENOENT;
+ if (!ehci_debug_root) {
+ retval = -ENOENT;
+ goto err_debug;
+ }
#endif
#ifdef PLATFORM_DRIVER
@@ -1104,7 +1111,9 @@ clean0:
#ifdef DEBUG
debugfs_remove(ehci_debug_root);
ehci_debug_root = NULL;
+err_debug:
#endif
+ clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
return retval;
}
module_init(ehci_hcd_init);
@@ -1126,6 +1135,7 @@ static void __exit ehci_hcd_cleanup(void)
#ifdef DEBUG
debugfs_remove(ehci_debug_root);
#endif
+ clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
}
module_exit(ehci_hcd_cleanup);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 740835bb857..218f9660d7e 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -236,10 +236,8 @@ 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)) {
- ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
+ (temp & PORT_SUSPEND))
temp |= PORT_RESUME;
- }
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
i = HCS_N_PORTS (ehci->hcs_params);
@@ -482,10 +480,9 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
* controller by the user.
*/
- if ((temp & mask) != 0
- || ((temp & PORT_RESUME) != 0
- && time_after_eq(jiffies,
- ehci->reset_done[i]))) {
+ if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend)
+ || (ehci->reset_done[i] && time_after_eq(
+ jiffies, ehci->reset_done[i]))) {
if (i < 7)
buf [0] |= 1 << (i + 1);
else
@@ -688,6 +685,7 @@ static int ehci_hub_control (
/* resume completed? */
else if (time_after_eq(jiffies,
ehci->reset_done[wIndex])) {
+ clear_bit(wIndex, &ehci->suspended_ports);
set_bit(wIndex, &ehci->port_c_suspend);
ehci->reset_done[wIndex] = 0;
@@ -734,6 +732,9 @@ static int ehci_hub_control (
ehci_readl(ehci, status_reg));
}
+ if (!(temp & (PORT_RESUME|PORT_RESET)))
+ ehci->reset_done[wIndex] = 0;
+
/* transfer dedicated ports to the companion hc */
if ((temp & PORT_CONNECT) &&
test_bit(wIndex, &ehci->companion_ports)) {
@@ -757,8 +758,17 @@ static int ehci_hub_control (
}
if (temp & PORT_PE)
status |= 1 << USB_PORT_FEAT_ENABLE;
- if (temp & (PORT_SUSPEND|PORT_RESUME))
+
+ /* maybe the port was unsuspended without our knowledge */
+ if (temp & (PORT_SUSPEND|PORT_RESUME)) {
status |= 1 << USB_PORT_FEAT_SUSPEND;
+ } else if (test_bit(wIndex, &ehci->suspended_ports)) {
+ clear_bit(wIndex, &ehci->suspended_ports);
+ ehci->reset_done[wIndex] = 0;
+ if (temp & PORT_PE)
+ set_bit(wIndex, &ehci->port_c_suspend);
+ }
+
if (temp & PORT_OC)
status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
if (temp & PORT_RESET)
@@ -803,6 +813,7 @@ static int ehci_hub_control (
|| (temp & PORT_RESET) != 0)
goto error;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+ set_bit(wIndex, &ehci->suspended_ports);
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
deleted file mode 100644
index 529590eb403..00000000000
--- a/drivers/usb/host/ehci-ppc-soc.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * EHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 2006-2007 Stefan Roese <sr@denx.de>, DENX Software Engineering
- *
- * Bus Glue for PPC On-Chip EHCI driver
- * Tested on AMCC 440EPx
- *
- * Based on "ehci-au1xxx.c" by K.Boge <karsten.boge@amd.com>
- *
- * This file is licenced under the GPL.
- */
-
-#include <linux/platform_device.h>
-
-extern int usb_disabled(void);
-
-/* called during probe() after chip reset completes */
-static int ehci_ppc_soc_setup(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int retval;
-
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
-
- retval = ehci_init(hcd);
- if (retval)
- return retval;
-
- ehci->sbrn = 0x20;
- return ehci_reset(ehci);
-}
-
-/**
- * usb_ehci_ppc_soc_probe - initialize PPC-SoC-based HCDs
- * Context: !in_interrupt()
- *
- * Allocates basic resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
- *
- */
-int usb_ehci_ppc_soc_probe(const struct hc_driver *driver,
- struct usb_hcd **hcd_out,
- struct platform_device *dev)
-{
- int retval;
- struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
-
- if (dev->resource[1].flags != IORESOURCE_IRQ) {
- pr_debug("resource[1] is not IORESOURCE_IRQ");
- retval = -ENOMEM;
- }
- hcd = usb_create_hcd(driver, &dev->dev, "PPC-SOC EHCI");
- if (!hcd)
- return -ENOMEM;
- hcd->rsrc_start = dev->resource[0].start;
- hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
-
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- pr_debug("request_mem_region failed");
- retval = -EBUSY;
- goto err1;
- }
-
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- pr_debug("ioremap failed");
- retval = -ENOMEM;
- goto err2;
- }
-
- ehci = hcd_to_ehci(hcd);
- ehci->big_endian_mmio = 1;
- ehci->big_endian_desc = 1;
- ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
-#if defined(CONFIG_440EPX)
- /*
- * 440EPx Errata USBH_3
- * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
- */
- out_be32((void *)((ulong)(&ehci->regs->command) + 0x8c), (1 << 0));
- ehci_dbg(ehci, "Break Memory Transfer (BMT) has beed enabled!\n");
-#endif
-
- retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
- if (retval == 0)
- return retval;
-
- iounmap(hcd->regs);
-err2:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err1:
- usb_put_hcd(hcd);
- return retval;
-}
-
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
-/**
- * usb_ehci_hcd_ppc_soc_remove - shutdown processing for PPC-SoC-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_ehci_hcd_ppc_soc_probe(), first invoking
- * the HCD's stop() method. It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
- *
- */
-void usb_ehci_ppc_soc_remove(struct usb_hcd *hcd, struct platform_device *dev)
-{
- usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
-}
-
-static const struct hc_driver ehci_ppc_soc_hc_driver = {
- .description = hcd_name,
- .product_desc = "PPC-SOC EHCI",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- /*
- * basic lifecycle operations
- */
- .reset = ehci_ppc_soc_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-};
-
-static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = NULL;
- int ret;
-
- pr_debug("In ehci_hcd_ppc_soc_drv_probe\n");
-
- if (usb_disabled())
- return -ENODEV;
-
- /* FIXME we only want one one probe() not two */
- ret = usb_ehci_ppc_soc_probe(&ehci_ppc_soc_hc_driver, &hcd, pdev);
- return ret;
-}
-
-static int ehci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- /* FIXME we only want one one remove() not two */
- usb_ehci_ppc_soc_remove(hcd, pdev);
- return 0;
-}
-
-MODULE_ALIAS("platform:ppc-soc-ehci");
-static struct platform_driver ehci_ppc_soc_driver = {
- .probe = ehci_hcd_ppc_soc_drv_probe,
- .remove = ehci_hcd_ppc_soc_drv_remove,
- .shutdown = usb_hcd_platform_shutdown,
- .driver = {
- .name = "ppc-soc-ehci",
- }
-};
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index b697a13364e..b11798d17ae 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -99,6 +99,8 @@ struct ehci_hcd { /* one per controller */
owned by the companion during a bus suspend */
unsigned long port_c_suspend; /* which ports have
the change-suspend feature turned on */
+ unsigned long suspended_ports; /* which ports are
+ suspended */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
@@ -181,14 +183,16 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
* the async ring; just the I/O watchdog. Note that if a
* SHRINK were pending, OFF would never be requested.
*/
- if (timer_pending(&ehci->watchdog)
- && ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
- & ehci->actions))
- return;
+ enum ehci_timer_action oldactions = ehci->actions;
if (!test_and_set_bit (action, &ehci->actions)) {
unsigned long t;
+ if (timer_pending(&ehci->watchdog)
+ && ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
+ & oldactions))
+ return;
+
switch (action) {
case TIMER_IO_WATCHDOG:
t = EHCI_IO_JIFFIES;
@@ -204,7 +208,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
break;
}
- mod_timer(&ehci->watchdog, t + jiffies);
+ mod_timer(&ehci->watchdog, round_jiffies(t + jiffies));
}
}
@@ -604,16 +608,7 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
/*
* Big-endian read/write functions are arch-specific.
* Other arches can be added if/when they're needed.
- *
- * REVISIT: arch/powerpc now has readl/writel_be, so the
- * definition below can die once the 4xx support is
- * finally ported over.
*/
-#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
-#define readl_be(addr) in_be32((__force unsigned *)addr)
-#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
-#endif
-
#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX)
#define readl_be(addr) __raw_readl((__force unsigned *)addr)
#define writel_be(val, addr) __raw_writel(val, (__force unsigned *)addr)
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
new file mode 100644
index 00000000000..64be4d88df1
--- /dev/null
+++ b/drivers/usb/host/hwa-hc.c
@@ -0,0 +1,925 @@
+/*
+ * Host Wire Adapter:
+ * Driver glue, HWA-specific functions, bridges to WAHC and WUSBHC
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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 HWA driver is a simple layer that forwards requests to the WAHC
+ * (Wire Adater Host Controller) or WUSBHC (Wireless USB Host
+ * Controller) layers.
+ *
+ * Host Wire Adapter is the 'WUSB 1.0 standard' name for Wireless-USB
+ * Host Controller that is connected to your system via USB (a USB
+ * dongle that implements a USB host...). There is also a Device Wired
+ * Adaptor, DWA (Wireless USB hub) that uses the same mechanism for
+ * transferring data (it is after all a USB host connected via
+ * Wireless USB), we have a common layer called Wire Adapter Host
+ * Controller that does all the hard work. The WUSBHC (Wireless USB
+ * Host Controller) is the part common to WUSB Host Controllers, the
+ * HWA and the PCI-based one, that is implemented following the WHCI
+ * spec. All these layers are implemented in ../wusbcore.
+ *
+ * The main functions are hwahc_op_urb_{en,de}queue(), that pass the
+ * job of converting a URB to a Wire Adapter
+ *
+ * Entry points:
+ *
+ * hwahc_driver_*() Driver initialization, registration and
+ * teardown.
+ *
+ * hwahc_probe() New device came up, create an instance for
+ * it [from device enumeration].
+ *
+ * hwahc_disconnect() Remove device instance [from device
+ * enumeration].
+ *
+ * [__]hwahc_op_*() Host-Wire-Adaptor specific functions for
+ * starting/stopping/etc (some might be made also
+ * DWA).
+ */
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include "../wusbcore/wa-hc.h"
+#include "../wusbcore/wusbhc.h"
+
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+struct hwahc {
+ struct wusbhc wusbhc; /* has to be 1st */
+ struct wahc wa;
+ u8 buffer[16]; /* for misc usb transactions */
+};
+
+/**
+ * FIXME should be wusbhc
+ *
+ * NOTE: we need to cache the Cluster ID because later...there is no
+ * way to get it :)
+ */
+static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id)
+{
+ int result;
+ struct wusbhc *wusbhc = &hwahc->wusbhc;
+ struct wahc *wa = &hwahc->wa;
+ struct device *dev = &wa->usb_iface->dev;
+
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_CLUSTER_ID,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ cluster_id,
+ wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, 1000 /* FIXME: arbitrary */);
+ if (result < 0)
+ dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n",
+ cluster_id, result);
+ else
+ wusbhc->cluster_id = cluster_id;
+ dev_info(dev, "Wireless USB Cluster ID set to 0x%02x\n", cluster_id);
+ return result;
+}
+
+static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
+{
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+
+ return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_NUM_DNTS,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ interval << 8 | slots,
+ wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, 1000 /* FIXME: arbitrary */);
+}
+
+/*
+ * Reset a WUSB host controller and wait for it to complete doing it.
+ *
+ * @usb_hcd: Pointer to WUSB Host Controller instance.
+ *
+ */
+static int hwahc_op_reset(struct usb_hcd *usb_hcd)
+{
+ int result;
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct device *dev = &hwahc->wa.usb_iface->dev;
+
+ d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
+ mutex_lock(&wusbhc->mutex);
+ wa_nep_disarm(&hwahc->wa);
+ result = __wa_set_feature(&hwahc->wa, WA_RESET);
+ if (result < 0) {
+ dev_err(dev, "error commanding HC to reset: %d\n", result);
+ goto error_unlock;
+ }
+ d_printf(3, dev, "reset: waiting for device to change state\n");
+ result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0);
+ if (result < 0) {
+ dev_err(dev, "error waiting for HC to reset: %d\n", result);
+ goto error_unlock;
+ }
+error_unlock:
+ mutex_unlock(&wusbhc->mutex);
+ d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
+ return result;
+}
+
+/*
+ * FIXME: break this function up
+ */
+static int hwahc_op_start(struct usb_hcd *usb_hcd)
+{
+ u8 addr;
+ int result;
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct device *dev = &hwahc->wa.usb_iface->dev;
+
+ /* Set up a Host Info WUSB Information Element */
+ d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
+ result = -ENOSPC;
+ mutex_lock(&wusbhc->mutex);
+ /* Start the numbering from the top so that the bottom
+ * range of the unauth addr space is used for devices,
+ * the top for HCs; use 0xfe - RC# */
+ addr = wusb_cluster_id_get();
+ if (addr == 0)
+ goto error_cluster_id_get;
+ result = __hwahc_set_cluster_id(hwahc, addr);
+ if (result < 0)
+ goto error_set_cluster_id;
+
+ result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "cannot listen to notifications: %d\n", result);
+ goto error_stop;
+ }
+ usb_hcd->uses_new_polling = 1;
+ usb_hcd->poll_rh = 1;
+ usb_hcd->state = HC_STATE_RUNNING;
+ result = 0;
+out:
+ mutex_unlock(&wusbhc->mutex);
+ d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
+ return result;
+
+error_stop:
+ __wa_stop(&hwahc->wa);
+error_set_cluster_id:
+ wusb_cluster_id_put(wusbhc->cluster_id);
+error_cluster_id_get:
+ goto out;
+
+}
+
+/*
+ * FIXME: break this function up
+ */
+static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
+{
+ int result;
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct device *dev = &hwahc->wa.usb_iface->dev;
+
+ /* Set up a Host Info WUSB Information Element */
+ d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
+ result = -ENOSPC;
+
+ result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
+ if (result < 0) {
+ dev_err(dev, "error commanding HC to start: %d\n", result);
+ goto error_stop;
+ }
+ result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
+ if (result < 0) {
+ dev_err(dev, "error waiting for HC to start: %d\n", result);
+ goto error_stop;
+ }
+ result = 0;
+out:
+ d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
+ return result;
+
+error_stop:
+ result = __wa_clear_feature(&hwahc->wa, WA_ENABLE);
+ goto out;
+}
+
+static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ dev_err(wusbhc->dev, "%s (%p [%p], 0x%lx) UNIMPLEMENTED\n", __func__,
+ usb_hcd, hwahc, *(unsigned long *) &msg);
+ return -ENOSYS;
+}
+
+static int hwahc_op_resume(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
+ usb_hcd, hwahc);
+ return -ENOSYS;
+}
+
+static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc)
+{
+ int result;
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct device *dev = &hwahc->wa.usb_iface->dev;
+
+ d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
+ /* Nothing for now */
+ d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
+ return;
+}
+
+/*
+ * No need to abort pipes, as when this is called, all the children
+ * has been disconnected and that has done it [through
+ * usb_disable_interface() -> usb_disable_endpoint() ->
+ * hwahc_op_ep_disable() - >rpipe_ep_disable()].
+ */
+static void hwahc_op_stop(struct usb_hcd *usb_hcd)
+{
+ int result;
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ struct device *dev = &wa->usb_iface->dev;
+
+ d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
+ mutex_lock(&wusbhc->mutex);
+ wusbhc_stop(wusbhc);
+ wa_nep_disarm(&hwahc->wa);
+ result = __wa_stop(&hwahc->wa);
+ wusb_cluster_id_put(wusbhc->cluster_id);
+ mutex_unlock(&wusbhc->mutex);
+ d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
+ return;
+}
+
+static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
+ usb_hcd, hwahc);
+ return -ENOSYS;
+}
+
+static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
+ gfp_t gfp)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ return wa_urb_enqueue(&hwahc->wa, urb->ep, urb, gfp);
+}
+
+static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb,
+ int status)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ return wa_urb_dequeue(&hwahc->wa, urb);
+}
+
+/*
+ * Release resources allocated for an endpoint
+ *
+ * If there is an associated rpipe to this endpoint, go ahead and put it.
+ */
+static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ rpipe_ep_disable(&hwahc->wa, ep);
+}
+
+/*
+ * Set the UWB MAS allocation for the WUSB cluster
+ *
+ * @stream_index: stream to use (-1 for cancelling the allocation)
+ * @mas: mas bitmap to use
+ */
+static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index,
+ const struct uwb_mas_bm *mas)
+{
+ int result;
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ struct device *dev = &wa->usb_iface->dev;
+ u8 mas_le[UWB_NUM_MAS/8];
+
+ /* Set the stream index */
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_STREAM_IDX,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ stream_index,
+ wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, 1000 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "Cannot set WUSB stream index: %d\n", result);
+ goto out;
+ }
+ uwb_mas_bm_copy_le(mas_le, mas);
+ /* Set the MAS allocation */
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_WUSB_MAS,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ mas_le, 32, 1000 /* FIXME: arbitrary */);
+ if (result < 0)
+ dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result);
+out:
+ return result;
+}
+
+/*
+ * Add an IE to the host's MMC
+ *
+ * @interval: See WUSB1.0[8.5.3.1]
+ * @repeat_cnt: See WUSB1.0[8.5.3.1]
+ * @handle: See WUSB1.0[8.5.3.1]
+ * @wuie: Pointer to the header of the WUSB IE data to add.
+ * MUST BE allocated in a kmalloc buffer (no stack or
+ * vmalloc).
+ *
+ * NOTE: the format of the WUSB IEs for MMCs are different to the
+ * normal MBOA MAC IEs (IE Id + Length in MBOA MAC vs. Length +
+ * Id in WUSB IEs). Standards...you gotta love'em.
+ */
+static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval,
+ u8 repeat_cnt, u8 handle,
+ struct wuie_hdr *wuie)
+{
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+
+ return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_ADD_MMC_IE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ interval << 8 | repeat_cnt,
+ handle << 8 | iface_no,
+ wuie, wuie->bLength, 1000 /* FIXME: arbitrary */);
+}
+
+/*
+ * Remove an IE to the host's MMC
+ *
+ * @handle: See WUSB1.0[8.5.3.1]
+ */
+static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
+{
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_REMOVE_MMC_IE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, handle << 8 | iface_no,
+ NULL, 0, 1000 /* FIXME: arbitrary */);
+}
+
+/*
+ * Update device information for a given fake port
+ *
+ * @port_idx: Fake port to which device is connected (wusbhc index, not
+ * USB port number).
+ */
+static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc,
+ struct wusb_dev *wusb_dev)
+{
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ struct hwa_dev_info *dev_info;
+ int ret;
+
+ /* fill out the Device Info buffer and send it */
+ dev_info = kzalloc(sizeof(struct hwa_dev_info), GFP_KERNEL);
+ if (!dev_info)
+ return -ENOMEM;
+ uwb_mas_bm_copy_le(dev_info->bmDeviceAvailability,
+ &wusb_dev->availability);
+ dev_info->bDeviceAddress = wusb_dev->addr;
+
+ /*
+ * If the descriptors haven't been read yet, use a default PHY
+ * rate of 53.3 Mbit/s only. The correct value will be used
+ * when this will be called again as part of the
+ * authentication process (which occurs after the descriptors
+ * have been read).
+ */
+ if (wusb_dev->wusb_cap_descr)
+ dev_info->wPHYRates = wusb_dev->wusb_cap_descr->wPHYRates;
+ else
+ dev_info->wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53);
+
+ ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ WUSB_REQ_SET_DEV_INFO,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, wusb_dev->port_idx << 8 | iface_no,
+ dev_info, sizeof(struct hwa_dev_info),
+ 1000 /* FIXME: arbitrary */);
+ kfree(dev_info);
+ return ret;
+}
+
+/*
+ * Set host's idea of which encryption (and key) method to use when
+ * talking to ad evice on a given port.
+ *
+ * If key is NULL, it means disable encryption for that "virtual port"
+ * (used when we disconnect).
+ */
+static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+ const void *key, size_t key_size,
+ u8 key_idx)
+{
+ int result = -ENOMEM;
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ struct usb_key_descriptor *keyd;
+ size_t keyd_len;
+
+ keyd_len = sizeof(*keyd) + key_size;
+ keyd = kzalloc(keyd_len, GFP_KERNEL);
+ if (keyd == NULL)
+ return -ENOMEM;
+
+ keyd->bLength = keyd_len;
+ keyd->bDescriptorType = USB_DT_KEY;
+ keyd->tTKID[0] = (tkid >> 0) & 0xff;
+ keyd->tTKID[1] = (tkid >> 8) & 0xff;
+ keyd->tTKID[2] = (tkid >> 16) & 0xff;
+ memcpy(keyd->bKeyData, key, key_size);
+
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_SET_DESCRIPTOR,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ USB_DT_KEY << 8 | key_idx,
+ port_idx << 8 | iface_no,
+ keyd, keyd_len, 1000 /* FIXME: arbitrary */);
+
+ memset(keyd, 0, sizeof(*keyd)); /* clear keys etc. */
+ kfree(keyd);
+ return result;
+}
+
+/*
+ * Set host's idea of which encryption (and key) method to use when
+ * talking to ad evice on a given port.
+ *
+ * If key is NULL, it means disable encryption for that "virtual port"
+ * (used when we disconnect).
+ */
+static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+ const void *key, size_t key_size)
+{
+ int result = -ENOMEM;
+ struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ struct wahc *wa = &hwahc->wa;
+ u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ u8 encryption_value;
+
+ /* Tell the host which key to use to talk to the device */
+ if (key) {
+ u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_PTK,
+ WUSB_KEY_INDEX_ORIGINATOR_HOST);
+
+ result = __hwahc_dev_set_key(wusbhc, port_idx, tkid,
+ key, key_size, key_idx);
+ if (result < 0)
+ goto error_set_key;
+ encryption_value = wusbhc->ccm1_etd->bEncryptionValue;
+ } else {
+ /* FIXME: this should come from wusbhc->etd[UNSECURE].value */
+ encryption_value = 0;
+ }
+
+ /* Set the encryption type for commmunicating with the device */
+ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_SET_ENCRYPTION,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ encryption_value, port_idx << 8 | iface_no,
+ NULL, 0, 1000 /* FIXME: arbitrary */);
+ if (result < 0)
+ dev_err(wusbhc->dev, "Can't set host's WUSB encryption for "
+ "port index %u to %s (value %d): %d\n", port_idx,
+ wusb_et_name(wusbhc->ccm1_etd->bEncryptionType),
+ wusbhc->ccm1_etd->bEncryptionValue, result);
+error_set_key:
+ return result;
+}
+
+/*
+ * Set host's GTK key
+ */
+static int __hwahc_op_set_gtk(struct wusbhc *wusbhc, u32 tkid,
+ const void *key, size_t key_size)
+{
+ u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK,
+ WUSB_KEY_INDEX_ORIGINATOR_HOST);
+
+ return __hwahc_dev_set_key(wusbhc, 0, tkid, key, key_size, key_idx);
+}
+
+/*
+ * Get the Wire Adapter class-specific descriptor
+ *
+ * NOTE: this descriptor comes with the big bundled configuration
+ * descriptor that includes the interfaces' and endpoints', so
+ * we just look for it in the cached copy kept by the USB stack.
+ *
+ * NOTE2: We convert LE fields to CPU order.
+ */
+static int wa_fill_descr(struct wahc *wa)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+ char *itr;
+ struct usb_device *usb_dev = wa->usb_dev;
+ struct usb_descriptor_header *hdr;
+ struct usb_wa_descriptor *wa_descr;
+ size_t itr_size, actconfig_idx;
+
+ actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
+ sizeof(usb_dev->config[0]);
+ itr = usb_dev->rawdescriptors[actconfig_idx];
+ itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
+ while (itr_size >= sizeof(*hdr)) {
+ hdr = (struct usb_descriptor_header *) itr;
+ d_printf(3, dev, "Extra device descriptor: "
+ "type %02x/%u bytes @ %zu (%zu left)\n",
+ hdr->bDescriptorType, hdr->bLength,
+ (itr - usb_dev->rawdescriptors[actconfig_idx]),
+ itr_size);
+ if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER)
+ goto found;
+ itr += hdr->bLength;
+ itr_size -= hdr->bLength;
+ }
+ dev_err(dev, "cannot find Wire Adapter Class descriptor\n");
+ return -ENODEV;
+
+found:
+ result = -EINVAL;
+ if (hdr->bLength > itr_size) { /* is it available? */
+ dev_err(dev, "incomplete Wire Adapter Class descriptor "
+ "(%zu bytes left, %u needed)\n",
+ itr_size, hdr->bLength);
+ goto error;
+ }
+ if (hdr->bLength < sizeof(*wa->wa_descr)) {
+ dev_err(dev, "short Wire Adapter Class descriptor\n");
+ goto error;
+ }
+ wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr;
+ /* Make LE fields CPU order */
+ wa_descr->bcdWAVersion = le16_to_cpu(wa_descr->bcdWAVersion);
+ wa_descr->wNumRPipes = le16_to_cpu(wa_descr->wNumRPipes);
+ wa_descr->wRPipeMaxBlock = le16_to_cpu(wa_descr->wRPipeMaxBlock);
+ if (wa_descr->bcdWAVersion > 0x0100)
+ dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n",
+ wa_descr->bcdWAVersion & 0xff00 >> 8,
+ wa_descr->bcdWAVersion & 0x00ff);
+ result = 0;
+error:
+ return result;
+}
+
+static struct hc_driver hwahc_hc_driver = {
+ .description = "hwa-hcd",
+ .product_desc = "Wireless USB HWA host controller",
+ .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd),
+ .irq = NULL, /* FIXME */
+ .flags = HCD_USB2, /* FIXME */
+ .reset = hwahc_op_reset,
+ .start = hwahc_op_start,
+ .pci_suspend = hwahc_op_suspend,
+ .pci_resume = hwahc_op_resume,
+ .stop = hwahc_op_stop,
+ .get_frame_number = hwahc_op_get_frame_number,
+ .urb_enqueue = hwahc_op_urb_enqueue,
+ .urb_dequeue = hwahc_op_urb_dequeue,
+ .endpoint_disable = hwahc_op_endpoint_disable,
+
+ .hub_status_data = wusbhc_rh_status_data,
+ .hub_control = wusbhc_rh_control,
+ .bus_suspend = wusbhc_rh_suspend,
+ .bus_resume = wusbhc_rh_resume,
+ .start_port_reset = wusbhc_rh_start_port_reset,
+};
+
+static int hwahc_security_create(struct hwahc *hwahc)
+{
+ int result;
+ struct wusbhc *wusbhc = &hwahc->wusbhc;
+ struct usb_device *usb_dev = hwahc->wa.usb_dev;
+ struct device *dev = &usb_dev->dev;
+ struct usb_security_descriptor *secd;
+ struct usb_encryption_descriptor *etd;
+ void *itr, *top;
+ size_t itr_size, needed, bytes;
+ u8 index;
+ char buf[64];
+
+ /* Find the host's security descriptors in the config descr bundle */
+ index = (usb_dev->actconfig - usb_dev->config) /
+ sizeof(usb_dev->config[0]);
+ itr = usb_dev->rawdescriptors[index];
+ itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
+ top = itr + itr_size;
+ result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
+ le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
+ USB_DT_SECURITY, (void **) &secd);
+ if (result == -1) {
+ dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
+ return 0;
+ }
+ needed = sizeof(*secd);
+ if (top - (void *)secd < needed) {
+ dev_err(dev, "BUG? Not enough data to process security "
+ "descriptor header (%zu bytes left vs %zu needed)\n",
+ top - (void *) secd, needed);
+ return 0;
+ }
+ needed = le16_to_cpu(secd->wTotalLength);
+ if (top - (void *)secd < needed) {
+ dev_err(dev, "BUG? Not enough data to process security "
+ "descriptors (%zu bytes left vs %zu needed)\n",
+ top - (void *) secd, needed);
+ return 0;
+ }
+ /* Walk over the sec descriptors and store CCM1's on wusbhc */
+ itr = (void *) secd + sizeof(*secd);
+ top = (void *) secd + le16_to_cpu(secd->wTotalLength);
+ index = 0;
+ bytes = 0;
+ while (itr < top) {
+ etd = itr;
+ if (top - itr < sizeof(*etd)) {
+ dev_err(dev, "BUG: bad host security descriptor; "
+ "not enough data (%zu vs %zu left)\n",
+ top - itr, sizeof(*etd));
+ break;
+ }
+ if (etd->bLength < sizeof(*etd)) {
+ dev_err(dev, "BUG: bad host encryption descriptor; "
+ "descriptor is too short "
+ "(%zu vs %zu needed)\n",
+ (size_t)etd->bLength, sizeof(*etd));
+ break;
+ }
+ itr += etd->bLength;
+ bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
+ "%s (0x%02x) ",
+ wusb_et_name(etd->bEncryptionType),
+ etd->bEncryptionValue);
+ wusbhc->ccm1_etd = etd;
+ }
+ dev_info(dev, "supported encryption types: %s\n", buf);
+ if (wusbhc->ccm1_etd == NULL) {
+ dev_err(dev, "E: host doesn't support CCM-1 crypto\n");
+ return 0;
+ }
+ /* Pretty print what we support */
+ return 0;
+}
+
+static void hwahc_security_release(struct hwahc *hwahc)
+{
+ /* nothing to do here so far... */
+}
+
+static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface)
+{
+ int result;
+ struct device *dev = &iface->dev;
+ struct wusbhc *wusbhc = &hwahc->wusbhc;
+ struct wahc *wa = &hwahc->wa;
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+
+ wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */
+ wa->usb_iface = usb_get_intf(iface);
+ wusbhc->dev = dev;
+ wusbhc->uwb_rc = uwb_rc_get_by_grandpa(iface->dev.parent);
+ if (wusbhc->uwb_rc == NULL) {
+ result = -ENODEV;
+ dev_err(dev, "Cannot get associated UWB Host Controller\n");
+ goto error_rc_get;
+ }
+ result = wa_fill_descr(wa); /* Get the device descriptor */
+ if (result < 0)
+ goto error_fill_descriptor;
+ if (wa->wa_descr->bNumPorts > USB_MAXCHILDREN) {
+ dev_err(dev, "FIXME: USB_MAXCHILDREN too low for WUSB "
+ "adapter (%u ports)\n", wa->wa_descr->bNumPorts);
+ wusbhc->ports_max = USB_MAXCHILDREN;
+ } else {
+ wusbhc->ports_max = wa->wa_descr->bNumPorts;
+ }
+ wusbhc->mmcies_max = wa->wa_descr->bNumMMCIEs;
+ wusbhc->start = __hwahc_op_wusbhc_start;
+ wusbhc->stop = __hwahc_op_wusbhc_stop;
+ wusbhc->mmcie_add = __hwahc_op_mmcie_add;
+ wusbhc->mmcie_rm = __hwahc_op_mmcie_rm;
+ wusbhc->dev_info_set = __hwahc_op_dev_info_set;
+ wusbhc->bwa_set = __hwahc_op_bwa_set;
+ wusbhc->set_num_dnts = __hwahc_op_set_num_dnts;
+ wusbhc->set_ptk = __hwahc_op_set_ptk;
+ wusbhc->set_gtk = __hwahc_op_set_gtk;
+ result = hwahc_security_create(hwahc);
+ if (result < 0) {
+ dev_err(dev, "Can't initialize security: %d\n", result);
+ goto error_security_create;
+ }
+ wa->wusb = wusbhc; /* FIXME: ugly, need to fix */
+ result = wusbhc_create(&hwahc->wusbhc);
+ if (result < 0) {
+ dev_err(dev, "Can't create WUSB HC structures: %d\n", result);
+ goto error_wusbhc_create;
+ }
+ result = wa_create(&hwahc->wa, iface);
+ if (result < 0)
+ goto error_wa_create;
+ return 0;
+
+error_wa_create:
+ wusbhc_destroy(&hwahc->wusbhc);
+error_wusbhc_create:
+ /* WA Descr fill allocs no resources */
+error_security_create:
+error_fill_descriptor:
+ uwb_rc_put(wusbhc->uwb_rc);
+error_rc_get:
+ usb_put_intf(iface);
+ usb_put_dev(usb_dev);
+ return result;
+}
+
+static void hwahc_destroy(struct hwahc *hwahc)
+{
+ struct wusbhc *wusbhc = &hwahc->wusbhc;
+
+ d_fnstart(1, NULL, "(hwahc %p)\n", hwahc);
+ mutex_lock(&wusbhc->mutex);
+ __wa_destroy(&hwahc->wa);
+ wusbhc_destroy(&hwahc->wusbhc);
+ hwahc_security_release(hwahc);
+ hwahc->wusbhc.dev = NULL;
+ uwb_rc_put(wusbhc->uwb_rc);
+ usb_put_intf(hwahc->wa.usb_iface);
+ usb_put_dev(hwahc->wa.usb_dev);
+ mutex_unlock(&wusbhc->mutex);
+ d_fnend(1, NULL, "(hwahc %p) = void\n", hwahc);
+}
+
+static void hwahc_init(struct hwahc *hwahc)
+{
+ wa_init(&hwahc->wa);
+}
+
+static int hwahc_probe(struct usb_interface *usb_iface,
+ const struct usb_device_id *id)
+{
+ int result;
+ struct usb_hcd *usb_hcd;
+ struct wusbhc *wusbhc;
+ struct hwahc *hwahc;
+ struct device *dev = &usb_iface->dev;
+
+ d_fnstart(4, dev, "(%p, %p)\n", usb_iface, id);
+ result = -ENOMEM;
+ usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa");
+ if (usb_hcd == NULL) {
+ dev_err(dev, "unable to allocate instance\n");
+ goto error_alloc;
+ }
+ usb_hcd->wireless = 1;
+ usb_hcd->flags |= HCD_FLAG_SAW_IRQ;
+ wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+ hwahc_init(hwahc);
+ result = hwahc_create(hwahc, usb_iface);
+ if (result < 0) {
+ dev_err(dev, "Cannot initialize internals: %d\n", result);
+ goto error_hwahc_create;
+ }
+ result = usb_add_hcd(usb_hcd, 0, 0);
+ if (result < 0) {
+ dev_err(dev, "Cannot add HCD: %d\n", result);
+ goto error_add_hcd;
+ }
+ result = wusbhc_b_create(&hwahc->wusbhc);
+ if (result < 0) {
+ dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result);
+ goto error_wusbhc_b_create;
+ }
+ d_fnend(4, dev, "(%p, %p) = 0\n", usb_iface, id);
+ return 0;
+
+error_wusbhc_b_create:
+ usb_remove_hcd(usb_hcd);
+error_add_hcd:
+ hwahc_destroy(hwahc);
+error_hwahc_create:
+ usb_put_hcd(usb_hcd);
+error_alloc:
+ d_fnend(4, dev, "(%p, %p) = %d\n", usb_iface, id, result);
+ return result;
+}
+
+static void hwahc_disconnect(struct usb_interface *usb_iface)
+{
+ struct usb_hcd *usb_hcd;
+ struct wusbhc *wusbhc;
+ struct hwahc *hwahc;
+
+ usb_hcd = usb_get_intfdata(usb_iface);
+ wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+ d_fnstart(1, NULL, "(hwahc %p [usb_iface %p])\n", hwahc, usb_iface);
+ wusbhc_b_destroy(&hwahc->wusbhc);
+ usb_remove_hcd(usb_hcd);
+ hwahc_destroy(hwahc);
+ usb_put_hcd(usb_hcd);
+ d_fnend(1, NULL, "(hwahc %p [usb_iface %p]) = void\n", hwahc,
+ usb_iface);
+}
+
+/** USB device ID's that we handle */
+static struct usb_device_id hwahc_id_table[] = {
+ /* FIXME: use class labels for this */
+ { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), },
+ {},
+};
+MODULE_DEVICE_TABLE(usb, hwahc_id_table);
+
+static struct usb_driver hwahc_driver = {
+ .name = "hwa-hc",
+ .probe = hwahc_probe,
+ .disconnect = hwahc_disconnect,
+ .id_table = hwahc_id_table,
+};
+
+static int __init hwahc_driver_init(void)
+{
+ int result;
+ result = usb_register(&hwahc_driver);
+ if (result < 0) {
+ printk(KERN_ERR "WA-CDS: Cannot register USB driver: %d\n",
+ result);
+ goto error_usb_register;
+ }
+ return 0;
+
+error_usb_register:
+ return result;
+
+}
+module_init(hwahc_driver_init);
+
+static void __exit hwahc_driver_exit(void)
+{
+ usb_deregister(&hwahc_driver);
+}
+module_exit(hwahc_driver_exit);
+
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Host Wired Adapter USB Host Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index ce1ca0ba051..4dda31b2689 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1562,11 +1562,12 @@ static int __devinit isp116x_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct isp116x *isp116x;
- struct resource *addr, *data;
+ struct resource *addr, *data, *ires;
void __iomem *addr_reg;
void __iomem *data_reg;
int irq;
int ret = 0;
+ unsigned long irqflags;
if (pdev->num_resources < 3) {
ret = -ENODEV;
@@ -1575,12 +1576,16 @@ static int __devinit isp116x_probe(struct platform_device *pdev)
data = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- irq = platform_get_irq(pdev, 0);
- if (!addr || !data || irq < 0) {
+ ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+ if (!addr || !data || !ires) {
ret = -ENODEV;
goto err1;
}
+ irq = ires->start;
+ irqflags = ires->flags & IRQF_TRIGGER_MASK;
+
if (pdev->dev.dma_mask) {
DBG("DMA not supported\n");
ret = -EINVAL;
@@ -1634,7 +1639,7 @@ static int __devinit isp116x_probe(struct platform_device *pdev)
goto err6;
}
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ ret = usb_add_hcd(hcd, irq, irqflags | IRQF_DISABLED);
if (ret)
goto err6;
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 051ef7b6bdc..af849f59613 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -218,7 +218,7 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
* and reading back and checking the contents are same or not
*/
if (reg_data != 0xFACE) {
- err("scratch register mismatch %x", reg_data);
+ dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
goto clean;
}
@@ -232,9 +232,10 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
devflags);
- pci_set_drvdata(dev, hcd);
- if (!hcd)
+ if (!IS_ERR(hcd)) {
+ pci_set_drvdata(dev, hcd);
return 0;
+ }
clean:
status = -ENODEV;
iounmap(iobase);
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 7cef1d2f7cc..d3269656aa4 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -649,7 +649,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
ohci_dbg_sw (ohci, &next, &size,
"bus %s, device %s\n"
"%s\n"
- "%s version " DRIVER_VERSION "\n",
+ "%s\n",
hcd->self.controller->bus->name,
dev_name(hcd->self.controller),
hcd->product_desc,
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 89901962cbf..8aa3f4556a3 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -46,7 +46,6 @@
#include "../core/hcd.h"
-#define DRIVER_VERSION "2006 August 04"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@@ -984,10 +983,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
/*-------------------------------------------------------------------------*/
-#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
-
MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE ("GPL");
#ifdef CONFIG_PCI
@@ -1078,12 +1075,18 @@ MODULE_LICENSE ("GPL");
#define SM501_OHCI_DRIVER ohci_hcd_sm501_driver
#endif
+#ifdef CONFIG_MFD_TC6393XB
+#include "ohci-tmio.c"
+#define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OF_PLATFORM_DRIVER) && \
!defined(SA1111_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && \
!defined(SM501_OHCI_DRIVER) && \
+ !defined(TMIO_OHCI_DRIVER) && \
!defined(SSB_OHCI_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
@@ -1095,9 +1098,10 @@ static int __init ohci_hcd_mod_init(void)
if (usb_disabled())
return -ENODEV;
- printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+ printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);
pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
sizeof (struct ed), sizeof (struct td));
+ set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
#ifdef DEBUG
ohci_debug_root = debugfs_create_dir("ohci", NULL);
@@ -1149,13 +1153,25 @@ static int __init ohci_hcd_mod_init(void)
goto error_sm501;
#endif
+#ifdef TMIO_OHCI_DRIVER
+ retval = platform_driver_register(&TMIO_OHCI_DRIVER);
+ if (retval < 0)
+ goto error_tmio;
+#endif
+
return retval;
/* Error path */
+#ifdef TMIO_OHCI_DRIVER
+ platform_driver_unregister(&TMIO_OHCI_DRIVER);
+ error_tmio:
+#endif
#ifdef SM501_OHCI_DRIVER
+ platform_driver_unregister(&SM501_OHCI_DRIVER);
error_sm501:
#endif
#ifdef SSB_OHCI_DRIVER
+ ssb_driver_unregister(&SSB_OHCI_DRIVER);
error_ssb:
#endif
#ifdef PCI_DRIVER
@@ -1184,12 +1200,16 @@ static int __init ohci_hcd_mod_init(void)
error_debug:
#endif
+ clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
return retval;
}
module_init(ohci_hcd_mod_init);
static void __exit ohci_hcd_mod_exit(void)
{
+#ifdef TMIO_OHCI_DRIVER
+ platform_driver_unregister(&TMIO_OHCI_DRIVER);
+#endif
#ifdef SM501_OHCI_DRIVER
platform_driver_unregister(&SM501_OHCI_DRIVER);
#endif
@@ -1214,6 +1234,7 @@ static void __exit ohci_hcd_mod_exit(void)
#ifdef DEBUG
debugfs_remove(ohci_debug_root);
#endif
+ clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
}
module_exit(ohci_hcd_mod_exit);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 7ea9a7b3115..32bbce9718f 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -359,21 +359,24 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
/* Carry out polling-, autostop-, and autoresume-related state changes */
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
- int any_connected)
+ int any_connected, int rhsc_status)
{
int poll_rh = 1;
- int rhsc;
+ int rhsc_enable;
- rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
- switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+ /* Some broken controllers never turn off RHCS in the interrupt
+ * status register. For their sake we won't re-enable RHSC
+ * interrupts if the interrupt bit is already active.
+ */
+ rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) &
+ OHCI_INTR_RHSC;
+ switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_OPER:
- /* If no status changes are pending, enable status-change
- * interrupts.
- */
- if (!rhsc && !changed) {
- rhsc = OHCI_INTR_RHSC;
- ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
+ /* If no status changes are pending, enable RHSC interrupts. */
+ if (!rhsc_enable && !rhsc_status && !changed) {
+ rhsc_enable = OHCI_INTR_RHSC;
+ ohci_writel(ohci, rhsc_enable, &ohci->regs->intrenable);
}
/* Keep on polling until we know a device is connected
@@ -383,7 +386,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
if (any_connected ||
!device_may_wakeup(&ohci_to_hcd(ohci)
->self.root_hub->dev)) {
- if (rhsc)
+ if (rhsc_enable)
poll_rh = 0;
} else {
ohci->autostop = 1;
@@ -396,34 +399,45 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
ohci->autostop = 0;
ohci->next_statechange = jiffies +
STATECHANGE_DELAY;
- } else if (rhsc && time_after_eq(jiffies,
+ } else if (time_after_eq(jiffies,
ohci->next_statechange)
&& !ohci->ed_rm_list
&& !(ohci->hc_control &
OHCI_SCHED_ENABLES)) {
ohci_rh_suspend(ohci, 1);
- poll_rh = 0;
+ if (rhsc_enable)
+ poll_rh = 0;
}
}
break;
- /* if there is a port change, autostart or ask to be resumed */
case OHCI_USB_SUSPEND:
case OHCI_USB_RESUME:
+ /* if there is a port change, autostart or ask to be resumed */
if (changed) {
if (ohci->autostop)
ohci_rh_resume(ohci);
else
usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
- } else {
- if (!rhsc && (ohci->autostop ||
- ohci_to_hcd(ohci)->self.root_hub->
- do_remote_wakeup))
- ohci_writel(ohci, OHCI_INTR_RHSC,
- &ohci->regs->intrenable);
- /* everything is idle, no need for polling */
+ /* If remote wakeup is disabled, stop polling */
+ } else if (!ohci->autostop &&
+ !ohci_to_hcd(ohci)->self.root_hub->
+ do_remote_wakeup) {
poll_rh = 0;
+
+ } else {
+ /* If no status changes are pending,
+ * enable RHSC interrupts
+ */
+ if (!rhsc_enable && !rhsc_status) {
+ rhsc_enable = OHCI_INTR_RHSC;
+ ohci_writel(ohci, rhsc_enable,
+ &ohci->regs->intrenable);
+ }
+ /* Keep polling until RHSC is enabled */
+ if (rhsc_enable)
+ poll_rh = 0;
}
break;
}
@@ -441,18 +455,22 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
* autostop isn't used when CONFIG_PM is turned off.
*/
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
- int any_connected)
+ int any_connected, int rhsc_status)
{
/* If RHSC is enabled, don't poll */
if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
return 0;
- /* If no status changes are pending, enable status-change interrupts */
- if (!changed) {
- ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
- return 0;
- }
- return 1;
+ /* If status changes are pending, continue polling.
+ * Conversely, if no status changes are pending but the RHSC
+ * status bit was set, then RHSC may be broken so continue polling.
+ */
+ if (changed || rhsc_status)
+ return 1;
+
+ /* It's safe to re-enable RHSC interrupts */
+ ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+ return 0;
}
#endif /* CONFIG_PM */
@@ -467,6 +485,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int i, changed = 0, length = 1;
int any_connected = 0;
+ int rhsc_status;
unsigned long flags;
spin_lock_irqsave (&ohci->lock, flags);
@@ -492,12 +511,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
length++;
}
- /* Some broken controllers never turn off RHCS in the interrupt
- * status register. For their sake we won't re-enable RHSC
- * interrupts if the flag is already set.
- */
- if (ohci_readl(ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC)
- changed = 1;
+ /* Clear the RHSC status flag before reading the port statuses */
+ ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrstatus);
+ rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
+ OHCI_INTR_RHSC;
/* look at each port */
for (i = 0; i < ohci->num_ports; i++) {
@@ -517,7 +534,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
}
hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed,
- any_connected);
+ any_connected, rhsc_status);
done:
spin_unlock_irqrestore (&ohci->lock, flags);
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 52218562962..91697bdb399 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -231,7 +231,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
omap_ohci_clock_power(1);
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
omap_1510_local_bus_power(1);
omap_1510_local_bus_init();
}
@@ -319,7 +319,7 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
if (IS_ERR(usb_host_ck))
return PTR_ERR(usb_host_ck);
- if (!cpu_is_omap1510())
+ if (!cpu_is_omap15xx())
usb_dc_ck = clk_get(0, "usb_dc_ck");
else
usb_dc_ck = clk_get(0, "lb_ck");
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 658a2a978c3..e306ca6aef3 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -331,7 +331,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
int ret = 0, irq;
- dev_dbg(&pdev->dev, "%s: " DRIVER_INFO " (pnx4008)\n", hcd_name);
+ dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (pnx4008)\n", hcd_name);
if (usb_disabled()) {
err("USB is disabled");
ret = -ENODEV;
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
new file mode 100644
index 00000000000..f9f134af0bd
--- /dev/null
+++ b/drivers/usb/host/ohci-tmio.c
@@ -0,0 +1,376 @@
+/*
+ * OHCI HCD(Host Controller Driver) for USB.
+ *
+ *(C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ *(C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ *(C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus glue for Toshiba Mobile IO(TMIO) Controller's OHCI core
+ * (C) Copyright 2005 Chris Humbert <mahadri-usb@drigon.com>
+ * (C) Copyright 2007, 2008 Dmitry Baryshkov <dbaryshkov@gmail.com>
+ *
+ * This is known to work with the following variants:
+ * TC6393XB revision 3 (32kB SRAM)
+ *
+ * The TMIO's OHCI core DMAs through a small internal buffer that
+ * is directly addressable by the CPU.
+ *
+ * Written from sparse documentation from Toshiba and Sharp's driver
+ * for the 2.4 kernel,
+ * usb-ohci-tc6393.c(C) Copyright 2004 Lineo Solutions, 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/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/namei.h>
+#include <linux/sched.h>*/
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tmio.h>
+#include <linux/dma-mapping.h>
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Configuration Register
+ */
+#define CCR_REVID 0x08 /* b Revision ID */
+#define CCR_BASE 0x10 /* l USB Control Register Base Address Low */
+#define CCR_ILME 0x40 /* b Internal Local Memory Enable */
+#define CCR_PM 0x4c /* w Power Management */
+#define CCR_INTC 0x50 /* b INT Control */
+#define CCR_LMW1L 0x54 /* w Local Memory Window 1 LMADRS Low */
+#define CCR_LMW1H 0x56 /* w Local Memory Window 1 LMADRS High */
+#define CCR_LMW1BL 0x58 /* w Local Memory Window 1 Base Address Low */
+#define CCR_LMW1BH 0x5A /* w Local Memory Window 1 Base Address High */
+#define CCR_LMW2L 0x5C /* w Local Memory Window 2 LMADRS Low */
+#define CCR_LMW2H 0x5E /* w Local Memory Window 2 LMADRS High */
+#define CCR_LMW2BL 0x60 /* w Local Memory Window 2 Base Address Low */
+#define CCR_LMW2BH 0x62 /* w Local Memory Window 2 Base Address High */
+#define CCR_MISC 0xFC /* b MISC */
+
+#define CCR_PM_GKEN 0x0001
+#define CCR_PM_CKRNEN 0x0002
+#define CCR_PM_USBPW1 0x0004
+#define CCR_PM_USBPW2 0x0008
+#define CCR_PM_USBPW3 0x0008
+#define CCR_PM_PMEE 0x0100
+#define CCR_PM_PMES 0x8000
+
+/*-------------------------------------------------------------------------*/
+
+struct tmio_hcd {
+ void __iomem *ccr;
+ spinlock_t lock; /* protects RMW cycles */
+};
+
+#define hcd_to_tmio(hcd) ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1))
+
+/*-------------------------------------------------------------------------*/
+
+static void tmio_write_pm(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct tmio_hcd *tmio = hcd_to_tmio(hcd);
+ u16 pm;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tmio->lock, flags);
+
+ pm = CCR_PM_GKEN | CCR_PM_CKRNEN |
+ CCR_PM_PMEE | CCR_PM_PMES;
+
+ tmio_iowrite16(pm, tmio->ccr + CCR_PM);
+ spin_unlock_irqrestore(&tmio->lock, flags);
+}
+
+static void tmio_stop_hc(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ struct tmio_hcd *tmio = hcd_to_tmio(hcd);
+ u16 pm;
+
+ pm = CCR_PM_GKEN | CCR_PM_CKRNEN;
+ switch (ohci->num_ports) {
+ default:
+ dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports);
+ case 3:
+ pm |= CCR_PM_USBPW3;
+ case 2:
+ pm |= CCR_PM_USBPW2;
+ case 1:
+ pm |= CCR_PM_USBPW1;
+ }
+ tmio_iowrite8(0, tmio->ccr + CCR_INTC);
+ tmio_iowrite8(0, tmio->ccr + CCR_ILME);
+ tmio_iowrite16(0, tmio->ccr + CCR_BASE);
+ tmio_iowrite16(0, tmio->ccr + CCR_BASE + 2);
+ tmio_iowrite16(pm, tmio->ccr + CCR_PM);
+}
+
+static void tmio_start_hc(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct tmio_hcd *tmio = hcd_to_tmio(hcd);
+ unsigned long base = hcd->rsrc_start;
+
+ tmio_write_pm(dev);
+ tmio_iowrite16(base, tmio->ccr + CCR_BASE);
+ tmio_iowrite16(base >> 16, tmio->ccr + CCR_BASE + 2);
+ tmio_iowrite8(1, tmio->ccr + CCR_ILME);
+ tmio_iowrite8(2, tmio->ccr + CCR_INTC);
+
+ dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n",
+ tmio_ioread8(tmio->ccr + CCR_REVID), hcd->rsrc_start, hcd->irq);
+}
+
+static int ohci_tmio_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+ err("can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct hc_driver ohci_tmio_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "TMIO OHCI USB Host Controller",
+ .hcd_priv_size = sizeof(struct ohci_hcd) + sizeof (struct tmio_hcd),
+
+ /* generic hardware linkage */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
+
+ /* basic lifecycle operations */
+ .start = ohci_tmio_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /* managing i/o requests and associated device resources */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /* scheduling support */
+ .get_frame_number = ohci_get_frame,
+
+ /* root hub support */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+static struct platform_driver ohci_hcd_tmio_driver;
+
+static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev)
+{
+ struct mfd_cell *cell = dev->dev.platform_data;
+ struct resource *regs = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ struct resource *config = platform_get_resource(dev, IORESOURCE_MEM, 1);
+ struct resource *sram = platform_get_resource(dev, IORESOURCE_MEM, 2);
+ int irq = platform_get_irq(dev, 0);
+ struct tmio_hcd *tmio;
+ struct ohci_hcd *ohci;
+ struct usb_hcd *hcd;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (!cell)
+ return -EINVAL;
+
+ hcd = usb_create_hcd(&ohci_tmio_hc_driver, &dev->dev, dev->dev.bus_id);
+ if (!hcd) {
+ ret = -ENOMEM;
+ goto err_usb_create_hcd;
+ }
+
+ hcd->rsrc_start = regs->start;
+ hcd->rsrc_len = regs->end - regs->start + 1;
+
+ tmio = hcd_to_tmio(hcd);
+
+ spin_lock_init(&tmio->lock);
+
+ tmio->ccr = ioremap(config->start, config->end - config->start + 1);
+ if (!tmio->ccr) {
+ ret = -ENOMEM;
+ goto err_ioremap_ccr;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ ret = -ENOMEM;
+ goto err_ioremap_regs;
+ }
+
+ if (!dma_declare_coherent_memory(&dev->dev, sram->start,
+ sram->start,
+ sram->end - sram->start + 1,
+ DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE)) {
+ ret = -EBUSY;
+ goto err_dma_declare;
+ }
+
+ if (cell->enable) {
+ ret = cell->enable(dev);
+ if (ret)
+ goto err_enable;
+ }
+
+ tmio_start_hc(dev);
+ ohci = hcd_to_ohci(hcd);
+ ohci_hcd_init(ohci);
+
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ if (ret)
+ goto err_add_hcd;
+
+ if (ret == 0)
+ return ret;
+
+ usb_remove_hcd(hcd);
+
+err_add_hcd:
+ tmio_stop_hc(dev);
+ if (cell->disable)
+ cell->disable(dev);
+err_enable:
+ dma_release_declared_memory(&dev->dev);
+err_dma_declare:
+ iounmap(hcd->regs);
+err_ioremap_regs:
+ iounmap(tmio->ccr);
+err_ioremap_ccr:
+ usb_put_hcd(hcd);
+err_usb_create_hcd:
+
+ return ret;
+}
+
+static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct tmio_hcd *tmio = hcd_to_tmio(hcd);
+ struct mfd_cell *cell = dev->dev.platform_data;
+
+ usb_remove_hcd(hcd);
+ tmio_stop_hc(dev);
+ if (cell->disable)
+ cell->disable(dev);
+ dma_release_declared_memory(&dev->dev);
+ iounmap(hcd->regs);
+ iounmap(tmio->ccr);
+ usb_put_hcd(hcd);
+
+ platform_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct mfd_cell *cell = dev->dev.platform_data;
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ struct tmio_hcd *tmio = hcd_to_tmio(hcd);
+ unsigned long flags;
+ u8 misc;
+ int ret;
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ spin_lock_irqsave(&tmio->lock, flags);
+
+ misc = tmio_ioread8(tmio->ccr + CCR_MISC);
+ misc |= 1 << 3; /* USSUSP */
+ tmio_iowrite8(misc, tmio->ccr + CCR_MISC);
+
+ spin_unlock_irqrestore(&tmio->lock, flags);
+
+ if (cell->suspend) {
+ ret = cell->suspend(dev);
+ if (ret)
+ return ret;
+ }
+
+ hcd->state = HC_STATE_SUSPENDED;
+
+ return 0;
+}
+
+static int ohci_hcd_tmio_drv_resume(struct platform_device *dev)
+{
+ struct mfd_cell *cell = dev->dev.platform_data;
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ struct tmio_hcd *tmio = hcd_to_tmio(hcd);
+ unsigned long flags;
+ u8 misc;
+ int ret;
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ if (cell->resume) {
+ ret = cell->resume(dev);
+ if (ret)
+ return ret;
+ }
+
+ tmio_start_hc(dev);
+
+ spin_lock_irqsave(&tmio->lock, flags);
+
+ misc = tmio_ioread8(tmio->ccr + CCR_MISC);
+ misc &= ~(1 << 3); /* USSUSP */
+ tmio_iowrite8(misc, tmio->ccr + CCR_MISC);
+
+ spin_unlock_irqrestore(&tmio->lock, flags);
+
+ ohci_finish_controller_resume(hcd);
+
+ return 0;
+}
+#else
+#define ohci_hcd_tmio_drv_suspend NULL
+#define ohci_hcd_tmio_drv_resume NULL
+#endif
+
+static struct platform_driver ohci_hcd_tmio_driver = {
+ .probe = ohci_hcd_tmio_drv_probe,
+ .remove = __devexit_p(ohci_hcd_tmio_drv_remove),
+ .shutdown = usb_hcd_platform_shutdown,
+ .suspend = ohci_hcd_tmio_drv_suspend,
+ .resume = ohci_hcd_tmio_drv_resume,
+ .driver = {
+ .name = "tmio-ohci",
+ .owner = THIS_MODULE,
+ },
+};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index faf622eafce..222011f6172 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -540,15 +540,7 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
* Big-endian read/write functions are arch-specific.
* Other arches can be added if/when they're needed.
*
- * REVISIT: arch/powerpc now has readl/writel_be, so the
- * definition below can die once the STB04xxx support is
- * finally ported over.
*/
-#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
-#define readl_be(addr) in_be32((__force unsigned *)addr)
-#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
-#endif
-
static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
__hc32 __iomem * regs)
{
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index ea7126f99ca..c18d8790c41 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -66,7 +66,7 @@ static unsigned short endian;
module_param(endian, ushort, 0644);
MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
-static unsigned short irq_sense = INTL;
+static unsigned short irq_sense = 0xff;
module_param(irq_sense, ushort, 0644);
MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
"(default=32)");
@@ -118,7 +118,7 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
r8a66597_write(r8a66597, SCKE, SYSCFG0);
tmp = r8a66597_read(r8a66597, SYSCFG0);
if (i++ > 1000) {
- err("register access fail.");
+ printk(KERN_ERR "r8a66597: register access fail.\n");
return -ENXIO;
}
} while ((tmp & SCKE) != SCKE);
@@ -128,7 +128,7 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
r8a66597_write(r8a66597, USBE, SYSCFG0);
tmp = r8a66597_read(r8a66597, SYSCFG0);
if (i++ > 1000) {
- err("register access fail.");
+ printk(KERN_ERR "r8a66597: register access fail.\n");
return -ENXIO;
}
} while ((tmp & USBE) != USBE);
@@ -141,7 +141,7 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
msleep(1);
tmp = r8a66597_read(r8a66597, SYSCFG0);
if (i++ > 500) {
- err("register access fail.");
+ printk(KERN_ERR "r8a66597: register access fail.\n");
return -ENXIO;
}
} while ((tmp & SCKE) != SCKE);
@@ -265,7 +265,7 @@ static void get_port_number(char *devpath, u16 *root_port, u16 *hub_port)
if (root_port) {
*root_port = (devpath[0] & 0x0F) - 1;
if (*root_port >= R8A66597_MAX_ROOT_HUB)
- err("illegal root port number");
+ printk(KERN_ERR "r8a66597: Illegal root port number.\n");
}
if (hub_port)
*hub_port = devpath[2] & 0x0F;
@@ -286,7 +286,7 @@ static u16 get_r8a66597_usb_speed(enum usb_device_speed speed)
usbspd = HSMODE;
break;
default:
- err("unknown speed");
+ printk(KERN_ERR "r8a66597: unknown speed\n");
break;
}
@@ -385,7 +385,7 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb)
struct r8a66597_device *dev;
if (is_hub_limit(urb->dev->devpath)) {
- err("Externel hub limit reached.");
+ dev_err(&urb->dev->dev, "External hub limit reached.\n");
return 0;
}
@@ -406,8 +406,9 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb)
return addr;
}
- err("cannot communicate with a USB device more than 10.(%x)",
- r8a66597->address_map);
+ dev_err(&urb->dev->dev,
+ "cannot communicate with a USB device more than 10.(%x)\n",
+ r8a66597->address_map);
return 0;
}
@@ -447,7 +448,8 @@ static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
do {
tmp = r8a66597_read(r8a66597, reg);
if (i++ > 1000000) {
- err("register%lx, loop %x is timeout", reg, loop);
+ printk(KERN_ERR "r8a66597: register%lx, loop %x "
+ "is timeout\n", reg, loop);
break;
}
ndelay(1);
@@ -675,7 +677,7 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
array[i++] = 1;
break;
default:
- err("Illegal type");
+ printk(KERN_ERR "r8a66597: Illegal type\n");
return 0;
}
@@ -705,7 +707,7 @@ static u16 get_r8a66597_type(__u8 type)
r8a66597_type = R8A66597_ISO;
break;
default:
- err("Illegal type");
+ printk(KERN_ERR "r8a66597: Illegal type\n");
r8a66597_type = 0x0000;
break;
}
@@ -724,7 +726,7 @@ static u16 get_bufnum(u16 pipenum)
else if (check_interrupt(pipenum))
bufnum = 4 + (pipenum - 6);
else
- err("Illegal pipenum (%d)", pipenum);
+ printk(KERN_ERR "r8a66597: Illegal pipenum (%d)\n", pipenum);
return bufnum;
}
@@ -740,7 +742,7 @@ static u16 get_buf_bsize(u16 pipenum)
else if (check_interrupt(pipenum))
buf_bsize = 0;
else
- err("Illegal pipenum (%d)", pipenum);
+ printk(KERN_ERR "r8a66597: Illegal pipenum (%d)\n", pipenum);
return buf_bsize;
}
@@ -760,10 +762,12 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
if ((r8a66597->dma_map & (1 << i)) != 0)
continue;
- info("address %d, EndpointAddress 0x%02x use DMA FIFO",
- usb_pipedevice(urb->pipe),
- info->dir_in ? USB_ENDPOINT_DIR_MASK + info->epnum
- : info->epnum);
+ dev_info(&dev->udev->dev,
+ "address %d, EndpointAddress 0x%02x use "
+ "DMA FIFO\n", usb_pipedevice(urb->pipe),
+ info->dir_in ?
+ USB_ENDPOINT_DIR_MASK + info->epnum
+ : info->epnum);
r8a66597->dma_map |= 1 << i;
dev->dma_map |= 1 << i;
@@ -1187,7 +1191,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
prepare_status_packet(r8a66597, td);
break;
default:
- err("invalid type.");
+ printk(KERN_ERR "r8a66597: invalid type.\n");
break;
}
@@ -1295,7 +1299,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
if (unlikely((tmp & FRDY) == 0)) {
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
- err("in fifo not ready (%d)", pipenum);
+ printk(KERN_ERR "r8a66597: in fifo not ready (%d)\n", pipenum);
finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
return;
}
@@ -1370,7 +1374,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
if (unlikely((tmp & FRDY) == 0)) {
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
- err("out write fifo not ready. (%d)", pipenum);
+ printk(KERN_ERR "r8a66597: out fifo not ready (%d)\n", pipenum);
finish_request(r8a66597, td, pipenum, urb, -EPIPE);
return;
}
@@ -2005,7 +2009,7 @@ static struct r8a66597_device *get_r8a66597_device(struct r8a66597 *r8a66597,
return dev;
}
- err("get_r8a66597_device fail.(%d)\n", addr);
+ printk(KERN_ERR "r8a66597: get_r8a66597_device fail.(%d)\n", addr);
return NULL;
}
@@ -2263,7 +2267,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
#define resource_len(r) (((r)->end - (r)->start) + 1)
static int __init r8a66597_probe(struct platform_device *pdev)
{
- struct resource *res = NULL;
+ struct resource *res = NULL, *ires;
int irq = -1;
void __iomem *reg = NULL;
struct usb_hcd *hcd = NULL;
@@ -2274,7 +2278,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
if (pdev->dev.dma_mask) {
ret = -EINVAL;
- err("dma not support");
+ dev_err(&pdev->dev, "dma not supported\n");
goto clean_up;
}
@@ -2282,21 +2286,25 @@ static int __init r8a66597_probe(struct platform_device *pdev)
(char *)hcd_name);
if (!res) {
ret = -ENODEV;
- err("platform_get_resource_byname error.");
+ dev_err(&pdev->dev, "platform_get_resource_byname error.\n");
goto clean_up;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
+ ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!ires) {
ret = -ENODEV;
- err("platform_get_irq error.");
+ dev_err(&pdev->dev,
+ "platform_get_resource IORESOURCE_IRQ error.\n");
goto clean_up;
}
+ irq = ires->start;
+ irq_trigger = ires->flags & IRQF_TRIGGER_MASK;
+
reg = ioremap(res->start, resource_len(res));
if (reg == NULL) {
ret = -ENOMEM;
- err("ioremap error.");
+ dev_err(&pdev->dev, "ioremap error.\n");
goto clean_up;
}
@@ -2304,7 +2312,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
hcd = usb_create_hcd(&r8a66597_hc_driver, &pdev->dev, (char *)hcd_name);
if (!hcd) {
ret = -ENOMEM;
- err("Failed to create hcd");
+ dev_err(&pdev->dev, "Failed to create hcd\n");
goto clean_up;
}
r8a66597 = hcd_to_r8a66597(hcd);
@@ -2329,13 +2337,33 @@ static int __init r8a66597_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&r8a66597->child_device);
hcd->rsrc_start = res->start;
- if (irq_sense == INTL)
- irq_trigger = IRQF_TRIGGER_LOW;
- else
- irq_trigger = IRQF_TRIGGER_FALLING;
+
+ /* irq_sense setting on cmdline takes precedence over resource
+ * settings, so the introduction of irqflags in IRQ resourse
+ * won't disturb existing setups */
+ switch (irq_sense) {
+ case INTL:
+ irq_trigger = IRQF_TRIGGER_LOW;
+ break;
+ case 0:
+ irq_trigger = IRQF_TRIGGER_FALLING;
+ break;
+ case 0xff:
+ if (irq_trigger)
+ irq_sense = (irq_trigger & IRQF_TRIGGER_LOW) ?
+ INTL : 0;
+ else {
+ irq_sense = INTL;
+ irq_trigger = IRQF_TRIGGER_LOW;
+ }
+ break;
+ default:
+ dev_err(&pdev->dev, "Unknown irq_sense value.\n");
+ }
+
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger);
if (ret != 0) {
- err("Failed to add hcd");
+ dev_err(&pdev->dev, "Failed to add hcd\n");
goto clean_up;
}
@@ -2364,7 +2392,8 @@ static int __init r8a66597_init(void)
if (usb_disabled())
return -ENODEV;
- info("driver %s, %s", hcd_name, DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": driver %s, %s\n", hcd_name,
+ DRIVER_VERSION);
return platform_driver_register(&r8a66597_driver);
}
module_init(r8a66597_init);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 8a74bbb57d0..e106e9d48d4 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1620,22 +1620,26 @@ sl811h_probe(struct platform_device *dev)
{
struct usb_hcd *hcd;
struct sl811 *sl811;
- struct resource *addr, *data;
+ struct resource *addr, *data, *ires;
int irq;
void __iomem *addr_reg;
void __iomem *data_reg;
int retval;
u8 tmp, ioaddr = 0;
+ unsigned long irqflags;
/* basic sanity checks first. board-specific init logic should
* have initialized these three resources and probably board
* specific platform_data. we don't probe for IRQs, and do only
* minimal sanity checking.
*/
- irq = platform_get_irq(dev, 0);
- if (dev->num_resources < 3 || irq < 0)
+ ires = platform_get_resource(dev, IORESOURCE_IRQ, 0);
+ if (dev->num_resources < 3 || !ires)
return -ENODEV;
+ irq = ires->start;
+ irqflags = ires->flags & IRQF_TRIGGER_MASK;
+
/* refuse to confuse usbcore */
if (dev->dev.dma_mask) {
DBG("no we won't dma\n");
@@ -1717,8 +1721,11 @@ sl811h_probe(struct platform_device *dev)
* triggers (e.g. most ARM CPUs). Initial driver stress testing
* was on a system with single edge triggering, so most sorts of
* triggering arrangement should work.
+ *
+ * Use resource IRQ flags if set by platform device setup.
*/
- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ irqflags |= IRQF_SHARED;
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | irqflags);
if (retval != 0)
goto err6;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 3a7bfe7a887..cf5e4cf7ea4 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -53,7 +53,6 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v3.0"
#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
Alan Stern"
@@ -951,12 +950,13 @@ static int __init uhci_hcd_init(void)
{
int retval = -ENOMEM;
- printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "%s\n",
- ignore_oc ? ", overcurrent ignored" : "");
-
if (usb_disabled())
return -ENODEV;
+ printk(KERN_INFO "uhci_hcd: " DRIVER_DESC "%s\n",
+ ignore_oc ? ", overcurrent ignored" : "");
+ set_bit(USB_UHCI_LOADED, &usb_hcds_loaded);
+
if (DEBUG_CONFIGURED) {
errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
if (!errbuf)
@@ -988,6 +988,7 @@ debug_failed:
errbuf_failed:
+ clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded);
return retval;
}
@@ -997,6 +998,7 @@ static void __exit uhci_hcd_cleanup(void)
kmem_cache_destroy(uhci_up_cachep);
debugfs_remove(uhci_debugfs_root);
kfree(errbuf);
+ clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded);
}
module_init(uhci_hcd_init);
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 1f0c2cf26e5..5631d89c873 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -1065,13 +1065,18 @@ static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
}
if (exponent < 0)
return -EINVAL;
- qh->period = 1 << exponent;
- qh->skel = SKEL_INDEX(exponent);
- /* For now, interrupt phase is fixed by the layout
- * of the QH lists. */
- qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
- ret = uhci_check_bandwidth(uhci, qh);
+ /* If the slot is full, try a lower period */
+ do {
+ qh->period = 1 << exponent;
+ qh->skel = SKEL_INDEX(exponent);
+
+ /* For now, interrupt phase is fixed by the layout
+ * of the QH lists.
+ */
+ qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
+ ret = uhci_check_bandwidth(uhci, qh);
+ } while (ret != 0 && --exponent >= 0);
if (ret)
return ret;
} else if (qh->period > urb->interval)
diff --git a/drivers/usb/host/whci/Kbuild b/drivers/usb/host/whci/Kbuild
new file mode 100644
index 00000000000..26a3871ea0f
--- /dev/null
+++ b/drivers/usb/host/whci/Kbuild
@@ -0,0 +1,11 @@
+obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o
+
+whci-hcd-y := \
+ asl.o \
+ hcd.o \
+ hw.o \
+ init.o \
+ int.o \
+ pzl.o \
+ qset.o \
+ wusb.o
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c
new file mode 100644
index 00000000000..4d7078e5057
--- /dev/null
+++ b/drivers/usb/host/whci/asl.c
@@ -0,0 +1,367 @@
+/*
+ * Wireless Host Controller (WHC) asynchronous schedule management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/uwb/umc.h>
+#include <linux/usb.h>
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+#include "../../wusbcore/wusbhc.h"
+
+#include "whcd.h"
+
+#if D_LOCAL >= 4
+static void dump_asl(struct whc *whc, const char *tag)
+{
+ struct device *dev = &whc->umc->dev;
+ struct whc_qset *qset;
+
+ d_printf(4, dev, "ASL %s\n", tag);
+
+ list_for_each_entry(qset, &whc->async_list, list_node) {
+ dump_qset(qset, dev);
+ }
+}
+#else
+static inline void dump_asl(struct whc *whc, const char *tag)
+{
+}
+#endif
+
+
+static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset,
+ struct whc_qset **next, struct whc_qset **prev)
+{
+ struct list_head *n, *p;
+
+ BUG_ON(list_empty(&whc->async_list));
+
+ n = qset->list_node.next;
+ if (n == &whc->async_list)
+ n = n->next;
+ p = qset->list_node.prev;
+ if (p == &whc->async_list)
+ p = p->prev;
+
+ *next = container_of(n, struct whc_qset, list_node);
+ *prev = container_of(p, struct whc_qset, list_node);
+
+}
+
+static void asl_qset_insert_begin(struct whc *whc, struct whc_qset *qset)
+{
+ list_move(&qset->list_node, &whc->async_list);
+ qset->in_sw_list = true;
+}
+
+static void asl_qset_insert(struct whc *whc, struct whc_qset *qset)
+{
+ struct whc_qset *next, *prev;
+
+ qset_clear(whc, qset);
+
+ /* Link into ASL. */
+ qset_get_next_prev(whc, qset, &next, &prev);
+ whc_qset_set_link_ptr(&qset->qh.link, next->qset_dma);
+ whc_qset_set_link_ptr(&prev->qh.link, qset->qset_dma);
+ qset->in_hw_list = true;
+}
+
+static void asl_qset_remove(struct whc *whc, struct whc_qset *qset)
+{
+ struct whc_qset *prev, *next;
+
+ qset_get_next_prev(whc, qset, &next, &prev);
+
+ list_move(&qset->list_node, &whc->async_removed_list);
+ qset->in_sw_list = false;
+
+ /*
+ * No more qsets in the ASL? The caller must stop the ASL as
+ * it's no longer valid.
+ */
+ if (list_empty(&whc->async_list))
+ return;
+
+ /* Remove from ASL. */
+ whc_qset_set_link_ptr(&prev->qh.link, next->qset_dma);
+ qset->in_hw_list = false;
+}
+
+/**
+ * process_qset - process any recently inactivated or halted qTDs in a
+ * qset.
+ *
+ * After inactive qTDs are removed, new qTDs can be added if the
+ * urb queue still contains URBs.
+ *
+ * Returns any additional WUSBCMD bits for the ASL sync command (i.e.,
+ * WUSBCMD_ASYNC_QSET_RM if a halted qset was removed).
+ */
+static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
+{
+ enum whc_update update = 0;
+ uint32_t status = 0;
+
+ while (qset->ntds) {
+ struct whc_qtd *td;
+ int t;
+
+ t = qset->td_start;
+ td = &qset->qtd[qset->td_start];
+ status = le32_to_cpu(td->status);
+
+ /*
+ * Nothing to do with a still active qTD.
+ */
+ if (status & QTD_STS_ACTIVE)
+ break;
+
+ if (status & QTD_STS_HALTED) {
+ /* Ug, an error. */
+ process_halted_qtd(whc, qset, td);
+ goto done;
+ }
+
+ /* Mmm, a completed qTD. */
+ process_inactive_qtd(whc, qset, td);
+ }
+
+ update |= qset_add_qtds(whc, qset);
+
+done:
+ /*
+ * Remove this qset from the ASL if requested, but only if has
+ * no qTDs.
+ */
+ if (qset->remove && qset->ntds == 0) {
+ asl_qset_remove(whc, qset);
+ update |= WHC_UPDATE_REMOVED;
+ }
+ return update;
+}
+
+void asl_start(struct whc *whc)
+{
+ struct whc_qset *qset;
+
+ qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
+
+ le_writeq(qset->qset_dma | QH_LINK_NTDS(8), whc->base + WUSBASYNCLISTADDR);
+
+ whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, WUSBCMD_ASYNC_EN);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_ASYNC_SCHED, WUSBSTS_ASYNC_SCHED,
+ 1000, "start ASL");
+}
+
+void asl_stop(struct whc *whc)
+{
+ whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, 0);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_ASYNC_SCHED, 0,
+ 1000, "stop ASL");
+}
+
+void asl_update(struct whc *whc, uint32_t wusbcmd)
+{
+ whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
+ wait_event(whc->async_list_wq,
+ (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0);
+}
+
+/**
+ * scan_async_work - scan the ASL for qsets to process.
+ *
+ * Process each qset in the ASL in turn and then signal the WHC that
+ * the ASL has been updated.
+ *
+ * Then start, stop or update the asynchronous schedule as required.
+ */
+void scan_async_work(struct work_struct *work)
+{
+ struct whc *whc = container_of(work, struct whc, async_work);
+ struct whc_qset *qset, *t;
+ enum whc_update update = 0;
+
+ spin_lock_irq(&whc->lock);
+
+ dump_asl(whc, "before processing");
+
+ /*
+ * Transerve the software list backwards so new qsets can be
+ * safely inserted into the ASL without making it non-circular.
+ */
+ list_for_each_entry_safe_reverse(qset, t, &whc->async_list, list_node) {
+ if (!qset->in_hw_list) {
+ asl_qset_insert(whc, qset);
+ update |= WHC_UPDATE_ADDED;
+ }
+
+ update |= process_qset(whc, qset);
+ }
+
+ dump_asl(whc, "after processing");
+
+ spin_unlock_irq(&whc->lock);
+
+ if (update) {
+ uint32_t wusbcmd = WUSBCMD_ASYNC_UPDATED | WUSBCMD_ASYNC_SYNCED_DB;
+ if (update & WHC_UPDATE_REMOVED)
+ wusbcmd |= WUSBCMD_ASYNC_QSET_RM;
+ asl_update(whc, wusbcmd);
+ }
+
+ /*
+ * Now that the ASL is updated, complete the removal of any
+ * removed qsets.
+ */
+ spin_lock(&whc->lock);
+
+ list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
+ qset_remove_complete(whc, qset);
+ }
+
+ spin_unlock(&whc->lock);
+}
+
+/**
+ * asl_urb_enqueue - queue an URB onto the asynchronous list (ASL).
+ * @whc: the WHCI host controller
+ * @urb: the URB to enqueue
+ * @mem_flags: flags for any memory allocations
+ *
+ * The qset for the endpoint is obtained and the urb queued on to it.
+ *
+ * Work is scheduled to update the hardware's view of the ASL.
+ */
+int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
+{
+ struct whc_qset *qset;
+ int err;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ qset = get_qset(whc, urb, GFP_ATOMIC);
+ if (qset == NULL)
+ err = -ENOMEM;
+ else
+ err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+ if (!err) {
+ usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
+ if (!qset->in_sw_list)
+ asl_qset_insert_begin(whc, qset);
+ }
+
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+ if (!err)
+ queue_work(whc->workqueue, &whc->async_work);
+
+ return 0;
+}
+
+/**
+ * asl_urb_dequeue - remove an URB (qset) from the async list.
+ * @whc: the WHCI host controller
+ * @urb: the URB to dequeue
+ * @status: the current status of the URB
+ *
+ * URBs that do yet have qTDs can simply be removed from the software
+ * queue, otherwise the qset must be removed from the ASL so the qTDs
+ * can be removed.
+ */
+int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
+{
+ struct whc_urb *wurb = urb->hcpriv;
+ struct whc_qset *qset = wurb->qset;
+ struct whc_std *std, *t;
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
+ if (ret < 0)
+ goto out;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+ if (std->urb == urb)
+ qset_free_std(whc, std);
+ else
+ std->qtd = NULL; /* so this std is re-added when the qset is */
+ }
+
+ asl_qset_remove(whc, qset);
+ wurb->status = status;
+ wurb->is_async = true;
+ queue_work(whc->workqueue, &wurb->dequeue_work);
+
+out:
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+ return ret;
+}
+
+/**
+ * asl_qset_delete - delete a qset from the ASL
+ */
+void asl_qset_delete(struct whc *whc, struct whc_qset *qset)
+{
+ qset->remove = 1;
+ queue_work(whc->workqueue, &whc->async_work);
+ qset_delete(whc, qset);
+}
+
+/**
+ * asl_init - initialize the asynchronous schedule list
+ *
+ * A dummy qset with no qTDs is added to the ASL to simplify removing
+ * qsets (no need to stop the ASL when the last qset is removed).
+ */
+int asl_init(struct whc *whc)
+{
+ struct whc_qset *qset;
+
+ qset = qset_alloc(whc, GFP_KERNEL);
+ if (qset == NULL)
+ return -ENOMEM;
+
+ asl_qset_insert_begin(whc, qset);
+ asl_qset_insert(whc, qset);
+
+ return 0;
+}
+
+/**
+ * asl_clean_up - free ASL resources
+ *
+ * The ASL is stopped and empty except for the dummy qset.
+ */
+void asl_clean_up(struct whc *whc)
+{
+ struct whc_qset *qset;
+
+ if (!list_empty(&whc->async_list)) {
+ qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
+ list_del(&qset->list_node);
+ qset_free(whc, qset);
+ }
+}
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c
new file mode 100644
index 00000000000..ef3ad4dca94
--- /dev/null
+++ b/drivers/usb/host/whci/hcd.c
@@ -0,0 +1,339 @@
+/*
+ * Wireless Host Controller (WHC) driver.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/uwb/umc.h>
+
+#include "../../wusbcore/wusbhc.h"
+
+#include "whcd.h"
+
+/*
+ * One time initialization.
+ *
+ * Nothing to do here.
+ */
+static int whc_reset(struct usb_hcd *usb_hcd)
+{
+ return 0;
+}
+
+/*
+ * Start the wireless host controller.
+ *
+ * Start device notification.
+ *
+ * Put hc into run state, set DNTS parameters.
+ */
+static int whc_start(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u8 bcid;
+ int ret;
+
+ mutex_lock(&wusbhc->mutex);
+
+ le_writel(WUSBINTR_GEN_CMD_DONE
+ | WUSBINTR_HOST_ERR
+ | WUSBINTR_ASYNC_SCHED_SYNCED
+ | WUSBINTR_DNTS_INT
+ | WUSBINTR_ERR_INT
+ | WUSBINTR_INT,
+ whc->base + WUSBINTR);
+
+ /* set cluster ID */
+ bcid = wusb_cluster_id_get();
+ ret = whc_set_cluster_id(whc, bcid);
+ if (ret < 0)
+ goto out;
+ wusbhc->cluster_id = bcid;
+
+ /* start HC */
+ whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);
+
+ usb_hcd->uses_new_polling = 1;
+ usb_hcd->poll_rh = 1;
+ usb_hcd->state = HC_STATE_RUNNING;
+
+out:
+ mutex_unlock(&wusbhc->mutex);
+ return ret;
+}
+
+
+/*
+ * Stop the wireless host controller.
+ *
+ * Stop device notification.
+ *
+ * Wait for pending transfer to stop? Put hc into stop state?
+ */
+static void whc_stop(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+
+ mutex_lock(&wusbhc->mutex);
+
+ wusbhc_stop(wusbhc);
+
+ /* stop HC */
+ le_writel(0, whc->base + WUSBINTR);
+ whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_HCHALTED, WUSBSTS_HCHALTED,
+ 100, "HC to halt");
+
+ wusb_cluster_id_put(wusbhc->cluster_id);
+
+ mutex_unlock(&wusbhc->mutex);
+}
+
+static int whc_get_frame_number(struct usb_hcd *usb_hcd)
+{
+ /* Frame numbers are not applicable to WUSB. */
+ return -ENOSYS;
+}
+
+
+/*
+ * Queue an URB to the ASL or PZL
+ */
+static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ int ret;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_INTERRUPT:
+ ret = pzl_urb_enqueue(whc, urb, mem_flags);
+ break;
+ case PIPE_ISOCHRONOUS:
+ dev_err(&whc->umc->dev, "isochronous transfers unsupported\n");
+ ret = -ENOTSUPP;
+ break;
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ default:
+ ret = asl_urb_enqueue(whc, urb, mem_flags);
+ break;
+ };
+
+ return ret;
+}
+
+/*
+ * Remove a queued URB from the ASL or PZL.
+ */
+static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ int ret;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_INTERRUPT:
+ ret = pzl_urb_dequeue(whc, urb, status);
+ break;
+ case PIPE_ISOCHRONOUS:
+ ret = -ENOTSUPP;
+ break;
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ default:
+ ret = asl_urb_dequeue(whc, urb, status);
+ break;
+ };
+
+ return ret;
+}
+
+/*
+ * Wait for all URBs to the endpoint to be completed, then delete the
+ * qset.
+ */
+static void whc_endpoint_disable(struct usb_hcd *usb_hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ struct whc_qset *qset;
+
+ qset = ep->hcpriv;
+ if (qset) {
+ ep->hcpriv = NULL;
+ if (usb_endpoint_xfer_bulk(&ep->desc)
+ || usb_endpoint_xfer_control(&ep->desc))
+ asl_qset_delete(whc, qset);
+ else
+ pzl_qset_delete(whc, qset);
+ }
+}
+
+static struct hc_driver whc_hc_driver = {
+ .description = "whci-hcd",
+ .product_desc = "Wireless host controller",
+ .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd),
+ .irq = whc_int_handler,
+ .flags = HCD_USB2,
+
+ .reset = whc_reset,
+ .start = whc_start,
+ .stop = whc_stop,
+ .get_frame_number = whc_get_frame_number,
+ .urb_enqueue = whc_urb_enqueue,
+ .urb_dequeue = whc_urb_dequeue,
+ .endpoint_disable = whc_endpoint_disable,
+
+ .hub_status_data = wusbhc_rh_status_data,
+ .hub_control = wusbhc_rh_control,
+ .bus_suspend = wusbhc_rh_suspend,
+ .bus_resume = wusbhc_rh_resume,
+ .start_port_reset = wusbhc_rh_start_port_reset,
+};
+
+static int whc_probe(struct umc_dev *umc)
+{
+ int ret = -ENOMEM;
+ struct usb_hcd *usb_hcd;
+ struct wusbhc *wusbhc = NULL;
+ struct whc *whc = NULL;
+ struct device *dev = &umc->dev;
+
+ usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
+ if (usb_hcd == NULL) {
+ dev_err(dev, "unable to create hcd\n");
+ goto error;
+ }
+
+ usb_hcd->wireless = 1;
+
+ wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ whc = wusbhc_to_whc(wusbhc);
+ whc->umc = umc;
+
+ ret = whc_init(whc);
+ if (ret)
+ goto error;
+
+ wusbhc->dev = dev;
+ wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
+ if (!wusbhc->uwb_rc) {
+ ret = -ENODEV;
+ dev_err(dev, "cannot get radio controller\n");
+ goto error;
+ }
+
+ if (whc->n_devices > USB_MAXCHILDREN) {
+ dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n",
+ whc->n_devices);
+ wusbhc->ports_max = USB_MAXCHILDREN;
+ } else
+ wusbhc->ports_max = whc->n_devices;
+ wusbhc->mmcies_max = whc->n_mmc_ies;
+ wusbhc->start = whc_wusbhc_start;
+ wusbhc->stop = whc_wusbhc_stop;
+ wusbhc->mmcie_add = whc_mmcie_add;
+ wusbhc->mmcie_rm = whc_mmcie_rm;
+ wusbhc->dev_info_set = whc_dev_info_set;
+ wusbhc->bwa_set = whc_bwa_set;
+ wusbhc->set_num_dnts = whc_set_num_dnts;
+ wusbhc->set_ptk = whc_set_ptk;
+ wusbhc->set_gtk = whc_set_gtk;
+
+ ret = wusbhc_create(wusbhc);
+ if (ret)
+ goto error_wusbhc_create;
+
+ ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED);
+ if (ret) {
+ dev_err(dev, "cannot add HCD: %d\n", ret);
+ goto error_usb_add_hcd;
+ }
+
+ ret = wusbhc_b_create(wusbhc);
+ if (ret) {
+ dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret);
+ goto error_wusbhc_b_create;
+ }
+
+ return 0;
+
+error_wusbhc_b_create:
+ usb_remove_hcd(usb_hcd);
+error_usb_add_hcd:
+ wusbhc_destroy(wusbhc);
+error_wusbhc_create:
+ uwb_rc_put(wusbhc->uwb_rc);
+error:
+ whc_clean_up(whc);
+ if (usb_hcd)
+ usb_put_hcd(usb_hcd);
+ return ret;
+}
+
+
+static void whc_remove(struct umc_dev *umc)
+{
+ struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev);
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+
+ if (usb_hcd) {
+ wusbhc_b_destroy(wusbhc);
+ usb_remove_hcd(usb_hcd);
+ wusbhc_destroy(wusbhc);
+ uwb_rc_put(wusbhc->uwb_rc);
+ whc_clean_up(whc);
+ usb_put_hcd(usb_hcd);
+ }
+}
+
+static struct umc_driver whci_hc_driver = {
+ .name = "whci-hcd",
+ .cap_id = UMC_CAP_ID_WHCI_WUSB_HC,
+ .probe = whc_probe,
+ .remove = whc_remove,
+};
+
+static int __init whci_hc_driver_init(void)
+{
+ return umc_driver_register(&whci_hc_driver);
+}
+module_init(whci_hc_driver_init);
+
+static void __exit whci_hc_driver_exit(void)
+{
+ umc_driver_unregister(&whci_hc_driver);
+}
+module_exit(whci_hc_driver_exit);
+
+/* PCI device ID's that we handle (so it gets loaded) */
+static struct pci_device_id whci_hcd_id_table[] = {
+ { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
+ { /* empty last entry */ }
+};
+MODULE_DEVICE_TABLE(pci, whci_hcd_id_table);
+
+MODULE_DESCRIPTION("WHCI Wireless USB host controller driver");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/whci/hw.c b/drivers/usb/host/whci/hw.c
new file mode 100644
index 00000000000..ac86e59c122
--- /dev/null
+++ b/drivers/usb/host/whci/hw.c
@@ -0,0 +1,87 @@
+/*
+ * Wireless Host Controller (WHC) hardware access helpers.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/uwb/umc.h>
+
+#include "../../wusbcore/wusbhc.h"
+
+#include "whcd.h"
+
+void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val)
+{
+ unsigned long flags;
+ u32 cmd;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ cmd = le_readl(whc->base + WUSBCMD);
+ cmd = (cmd & ~mask) | val;
+ le_writel(cmd, whc->base + WUSBCMD);
+
+ spin_unlock_irqrestore(&whc->lock, flags);
+}
+
+/**
+ * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register
+ * @whc: the WHCI HC
+ * @cmd: command to start.
+ * @params: parameters for the command (the WUSBGENCMDPARAMS register value).
+ * @addr: pointer to any data for the command (may be NULL).
+ * @len: length of the data (if any).
+ */
+int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len)
+{
+ unsigned long flags;
+ dma_addr_t dma_addr;
+ int t;
+
+ mutex_lock(&whc->mutex);
+
+ /* Wait for previous command to complete. */
+ t = wait_event_timeout(whc->cmd_wq,
+ (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0,
+ WHC_GENCMD_TIMEOUT_MS);
+ if (t == 0) {
+ dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n",
+ le_readl(whc->base + WUSBGENCMDSTS),
+ le_readl(whc->base + WUSBGENCMDPARAMS));
+ return -ETIMEDOUT;
+ }
+
+ if (addr) {
+ memcpy(whc->gen_cmd_buf, addr, len);
+ dma_addr = whc->gen_cmd_buf_dma;
+ } else
+ dma_addr = 0;
+
+ /* Poke registers to start cmd. */
+ spin_lock_irqsave(&whc->lock, flags);
+
+ le_writel(params, whc->base + WUSBGENCMDPARAMS);
+ le_writeq(dma_addr, whc->base + WUSBGENADDR);
+
+ le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd,
+ whc->base + WUSBGENCMDSTS);
+
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+ mutex_unlock(&whc->mutex);
+
+ return 0;
+}
diff --git a/drivers/usb/host/whci/init.c b/drivers/usb/host/whci/init.c
new file mode 100644
index 00000000000..34a783cb013
--- /dev/null
+++ b/drivers/usb/host/whci/init.c
@@ -0,0 +1,188 @@
+/*
+ * Wireless Host Controller (WHC) initialization.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/uwb/umc.h>
+
+#include "../../wusbcore/wusbhc.h"
+
+#include "whcd.h"
+
+/*
+ * Reset the host controller.
+ */
+static void whc_hw_reset(struct whc *whc)
+{
+ le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0,
+ 100, "reset");
+}
+
+static void whc_hw_init_di_buf(struct whc *whc)
+{
+ int d;
+
+ /* Disable all entries in the Device Information buffer. */
+ for (d = 0; d < whc->n_devices; d++)
+ whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE;
+
+ le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR);
+}
+
+static void whc_hw_init_dn_buf(struct whc *whc)
+{
+ /* Clear the Device Notification buffer to ensure the V (valid)
+ * bits are clear. */
+ memset(whc->dn_buf, 0, 4096);
+
+ le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR);
+}
+
+int whc_init(struct whc *whc)
+{
+ u32 whcsparams;
+ int ret, i;
+ resource_size_t start, len;
+
+ spin_lock_init(&whc->lock);
+ mutex_init(&whc->mutex);
+ init_waitqueue_head(&whc->cmd_wq);
+ init_waitqueue_head(&whc->async_list_wq);
+ init_waitqueue_head(&whc->periodic_list_wq);
+ whc->workqueue = create_singlethread_workqueue(dev_name(&whc->umc->dev));
+ if (whc->workqueue == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ INIT_WORK(&whc->dn_work, whc_dn_work);
+
+ INIT_WORK(&whc->async_work, scan_async_work);
+ INIT_LIST_HEAD(&whc->async_list);
+ INIT_LIST_HEAD(&whc->async_removed_list);
+
+ INIT_WORK(&whc->periodic_work, scan_periodic_work);
+ for (i = 0; i < 5; i++)
+ INIT_LIST_HEAD(&whc->periodic_list[i]);
+ INIT_LIST_HEAD(&whc->periodic_removed_list);
+
+ /* Map HC registers. */
+ start = whc->umc->resource.start;
+ len = whc->umc->resource.end - start + 1;
+ if (!request_mem_region(start, len, "whci-hc")) {
+ dev_err(&whc->umc->dev, "can't request HC region\n");
+ ret = -EBUSY;
+ goto error;
+ }
+ whc->base_phys = start;
+ whc->base = ioremap(start, len);
+ if (!whc->base) {
+ dev_err(&whc->umc->dev, "ioremap\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ whc_hw_reset(whc);
+
+ /* Read maximum number of devices, keys and MMC IEs. */
+ whcsparams = le_readl(whc->base + WHCSPARAMS);
+ whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
+ whc->n_keys = WHCSPARAMS_TO_N_KEYS(whcsparams);
+ whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);
+
+ dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
+ whc->n_devices, whc->n_keys, whc->n_mmc_ies);
+
+ whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
+ sizeof(struct whc_qset), 64, 0);
+ if (whc->qset_pool == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = asl_init(whc);
+ if (ret < 0)
+ goto error;
+ ret = pzl_init(whc);
+ if (ret < 0)
+ goto error;
+
+ /* Allocate and initialize a buffer for generic commands, the
+ Device Information buffer, and the Device Notification
+ buffer. */
+
+ whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
+ &whc->gen_cmd_buf_dma, GFP_KERNEL);
+ if (whc->gen_cmd_buf == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
+ sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
+ &whc->dn_buf_dma, GFP_KERNEL);
+ if (!whc->dn_buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ whc_hw_init_dn_buf(whc);
+
+ whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
+ sizeof(struct di_buf_entry) * whc->n_devices,
+ &whc->di_buf_dma, GFP_KERNEL);
+ if (!whc->di_buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ whc_hw_init_di_buf(whc);
+
+ return 0;
+
+error:
+ whc_clean_up(whc);
+ return ret;
+}
+
+void whc_clean_up(struct whc *whc)
+{
+ resource_size_t len;
+
+ if (whc->di_buf)
+ dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices,
+ whc->di_buf, whc->di_buf_dma);
+ if (whc->dn_buf)
+ dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
+ whc->dn_buf, whc->dn_buf_dma);
+ if (whc->gen_cmd_buf)
+ dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
+ whc->gen_cmd_buf, whc->gen_cmd_buf_dma);
+
+ pzl_clean_up(whc);
+ asl_clean_up(whc);
+
+ if (whc->qset_pool)
+ dma_pool_destroy(whc->qset_pool);
+
+ len = whc->umc->resource.end - whc->umc->resource.start + 1;
+ if (whc->base)
+ iounmap(whc->base);
+ if (whc->base_phys)
+ release_mem_region(whc->base_phys, len);
+
+ if (whc->workqueue)
+ destroy_workqueue(whc->workqueue);
+}
diff --git a/drivers/usb/host/whci/int.c b/drivers/usb/host/whci/int.c
new file mode 100644
index 00000000000..fce01174aa9
--- /dev/null
+++ b/drivers/usb/host/whci/int.c
@@ -0,0 +1,95 @@
+/*
+ * Wireless Host Controller (WHC) interrupt handling.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/uwb/umc.h>
+
+#include "../../wusbcore/wusbhc.h"
+
+#include "whcd.h"
+
+static void transfer_done(struct whc *whc)
+{
+ queue_work(whc->workqueue, &whc->async_work);
+ queue_work(whc->workqueue, &whc->periodic_work);
+}
+
+irqreturn_t whc_int_handler(struct usb_hcd *hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u32 sts;
+
+ sts = le_readl(whc->base + WUSBSTS);
+ if (!(sts & WUSBSTS_INT_MASK))
+ return IRQ_NONE;
+ le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS);
+
+ if (sts & WUSBSTS_GEN_CMD_DONE)
+ wake_up(&whc->cmd_wq);
+
+ if (sts & WUSBSTS_HOST_ERR)
+ dev_err(&whc->umc->dev, "FIXME: host system error\n");
+
+ if (sts & WUSBSTS_ASYNC_SCHED_SYNCED)
+ wake_up(&whc->async_list_wq);
+
+ if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED)
+ wake_up(&whc->periodic_list_wq);
+
+ if (sts & WUSBSTS_DNTS_INT)
+ queue_work(whc->workqueue, &whc->dn_work);
+
+ /*
+ * A transfer completed (see [WHCI] section 4.7.1.2 for when
+ * this occurs).
+ */
+ if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT))
+ transfer_done(whc);
+
+ return IRQ_HANDLED;
+}
+
+static int process_dn_buf(struct whc *whc)
+{
+ struct wusbhc *wusbhc = &whc->wusbhc;
+ struct dn_buf_entry *dn;
+ int processed = 0;
+
+ for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) {
+ if (dn->status & WHC_DN_STATUS_VALID) {
+ wusbhc_handle_dn(wusbhc, dn->src_addr,
+ (struct wusb_dn_hdr *)dn->dn_data,
+ dn->msg_size);
+ dn->status &= ~WHC_DN_STATUS_VALID;
+ processed++;
+ }
+ }
+ return processed;
+}
+
+void whc_dn_work(struct work_struct *work)
+{
+ struct whc *whc = container_of(work, struct whc, dn_work);
+ int processed;
+
+ do {
+ processed = process_dn_buf(whc);
+ } while (processed);
+}
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c
new file mode 100644
index 00000000000..8d62df0c330
--- /dev/null
+++ b/drivers/usb/host/whci/pzl.c
@@ -0,0 +1,398 @@
+/*
+ * Wireless Host Controller (WHC) periodic schedule management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/uwb/umc.h>
+#include <linux/usb.h>
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+#include "../../wusbcore/wusbhc.h"
+
+#include "whcd.h"
+
+#if D_LOCAL >= 4
+static void dump_pzl(struct whc *whc, const char *tag)
+{
+ struct device *dev = &whc->umc->dev;
+ struct whc_qset *qset;
+ int period = 0;
+
+ d_printf(4, dev, "PZL %s\n", tag);
+
+ for (period = 0; period < 5; period++) {
+ d_printf(4, dev, "Period %d\n", period);
+ list_for_each_entry(qset, &whc->periodic_list[period], list_node) {
+ dump_qset(qset, dev);
+ }
+ }
+}
+#else
+static inline void dump_pzl(struct whc *whc, const char *tag)
+{
+}
+#endif
+
+static void update_pzl_pointers(struct whc *whc, int period, u64 addr)
+{
+ switch (period) {
+ case 0:
+ whc_qset_set_link_ptr(&whc->pz_list[0], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[2], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[4], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[6], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[8], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[10], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[12], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[14], addr);
+ break;
+ case 1:
+ whc_qset_set_link_ptr(&whc->pz_list[1], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[5], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[9], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[13], addr);
+ break;
+ case 2:
+ whc_qset_set_link_ptr(&whc->pz_list[3], addr);
+ whc_qset_set_link_ptr(&whc->pz_list[11], addr);
+ break;
+ case 3:
+ whc_qset_set_link_ptr(&whc->pz_list[7], addr);
+ break;
+ case 4:
+ whc_qset_set_link_ptr(&whc->pz_list[15], addr);
+ break;
+ }
+}
+
+/*
+ * Return the 'period' to use for this qset. The minimum interval for
+ * the endpoint is used so whatever urbs are submitted the device is
+ * polled often enough.
+ */
+static int qset_get_period(struct whc *whc, struct whc_qset *qset)
+{
+ uint8_t bInterval = qset->ep->desc.bInterval;
+
+ if (bInterval < 6)
+ bInterval = 6;
+ if (bInterval > 10)
+ bInterval = 10;
+ return bInterval - 6;
+}
+
+static void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset)
+{
+ int period;
+
+ period = qset_get_period(whc, qset);
+
+ qset_clear(whc, qset);
+ list_move(&qset->list_node, &whc->periodic_list[period]);
+ qset->in_sw_list = true;
+}
+
+static void pzl_qset_remove(struct whc *whc, struct whc_qset *qset)
+{
+ list_move(&qset->list_node, &whc->periodic_removed_list);
+ qset->in_hw_list = false;
+ qset->in_sw_list = false;
+}
+
+/**
+ * pzl_process_qset - process any recently inactivated or halted qTDs
+ * in a qset.
+ *
+ * After inactive qTDs are removed, new qTDs can be added if the
+ * urb queue still contains URBs.
+ *
+ * Returns the schedule updates required.
+ */
+static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
+{
+ enum whc_update update = 0;
+ uint32_t status = 0;
+
+ while (qset->ntds) {
+ struct whc_qtd *td;
+ int t;
+
+ t = qset->td_start;
+ td = &qset->qtd[qset->td_start];
+ status = le32_to_cpu(td->status);
+
+ /*
+ * Nothing to do with a still active qTD.
+ */
+ if (status & QTD_STS_ACTIVE)
+ break;
+
+ if (status & QTD_STS_HALTED) {
+ /* Ug, an error. */
+ process_halted_qtd(whc, qset, td);
+ goto done;
+ }
+
+ /* Mmm, a completed qTD. */
+ process_inactive_qtd(whc, qset, td);
+ }
+
+ update |= qset_add_qtds(whc, qset);
+
+done:
+ /*
+ * If there are no qTDs in this qset, remove it from the PZL.
+ */
+ if (qset->remove && qset->ntds == 0) {
+ pzl_qset_remove(whc, qset);
+ update |= WHC_UPDATE_REMOVED;
+ }
+
+ return update;
+}
+
+/**
+ * pzl_start - start the periodic schedule
+ * @whc: the WHCI host controller
+ *
+ * The PZL must be valid (e.g., all entries in the list should have
+ * the T bit set).
+ */
+void pzl_start(struct whc *whc)
+{
+ le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
+
+ whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED,
+ 1000, "start PZL");
+}
+
+/**
+ * pzl_stop - stop the periodic schedule
+ * @whc: the WHCI host controller
+ */
+void pzl_stop(struct whc *whc)
+{
+ whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0);
+ whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+ WUSBSTS_PERIODIC_SCHED, 0,
+ 1000, "stop PZL");
+}
+
+void pzl_update(struct whc *whc, uint32_t wusbcmd)
+{
+ whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
+ wait_event(whc->periodic_list_wq,
+ (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0);
+}
+
+static void update_pzl_hw_view(struct whc *whc)
+{
+ struct whc_qset *qset, *t;
+ int period;
+ u64 tmp_qh = 0;
+
+ for (period = 0; period < 5; period++) {
+ list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
+ whc_qset_set_link_ptr(&qset->qh.link, tmp_qh);
+ tmp_qh = qset->qset_dma;
+ qset->in_hw_list = true;
+ }
+ update_pzl_pointers(whc, period, tmp_qh);
+ }
+}
+
+/**
+ * scan_periodic_work - scan the PZL for qsets to process.
+ *
+ * Process each qset in the PZL in turn and then signal the WHC that
+ * the PZL has been updated.
+ *
+ * Then start, stop or update the periodic schedule as required.
+ */
+void scan_periodic_work(struct work_struct *work)
+{
+ struct whc *whc = container_of(work, struct whc, periodic_work);
+ struct whc_qset *qset, *t;
+ enum whc_update update = 0;
+ int period;
+
+ spin_lock_irq(&whc->lock);
+
+ dump_pzl(whc, "before processing");
+
+ for (period = 4; period >= 0; period--) {
+ list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
+ if (!qset->in_hw_list)
+ update |= WHC_UPDATE_ADDED;
+ update |= pzl_process_qset(whc, qset);
+ }
+ }
+
+ if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED))
+ update_pzl_hw_view(whc);
+
+ dump_pzl(whc, "after processing");
+
+ spin_unlock_irq(&whc->lock);
+
+ if (update) {
+ uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB;
+ if (update & WHC_UPDATE_REMOVED)
+ wusbcmd |= WUSBCMD_PERIODIC_QSET_RM;
+ pzl_update(whc, wusbcmd);
+ }
+
+ /*
+ * Now that the PZL is updated, complete the removal of any
+ * removed qsets.
+ */
+ spin_lock(&whc->lock);
+
+ list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
+ qset_remove_complete(whc, qset);
+ }
+
+ spin_unlock(&whc->lock);
+}
+
+/**
+ * pzl_urb_enqueue - queue an URB onto the periodic list (PZL)
+ * @whc: the WHCI host controller
+ * @urb: the URB to enqueue
+ * @mem_flags: flags for any memory allocations
+ *
+ * The qset for the endpoint is obtained and the urb queued on to it.
+ *
+ * Work is scheduled to update the hardware's view of the PZL.
+ */
+int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
+{
+ struct whc_qset *qset;
+ int err;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ qset = get_qset(whc, urb, GFP_ATOMIC);
+ if (qset == NULL)
+ err = -ENOMEM;
+ else
+ err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+ if (!err) {
+ usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
+ if (!qset->in_sw_list)
+ qset_insert_in_sw_list(whc, qset);
+ }
+
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+ if (!err)
+ queue_work(whc->workqueue, &whc->periodic_work);
+
+ return 0;
+}
+
+/**
+ * pzl_urb_dequeue - remove an URB (qset) from the periodic list
+ * @whc: the WHCI host controller
+ * @urb: the URB to dequeue
+ * @status: the current status of the URB
+ *
+ * URBs that do yet have qTDs can simply be removed from the software
+ * queue, otherwise the qset must be removed so the qTDs can be safely
+ * removed.
+ */
+int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
+{
+ struct whc_urb *wurb = urb->hcpriv;
+ struct whc_qset *qset = wurb->qset;
+ struct whc_std *std, *t;
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
+
+ ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
+ if (ret < 0)
+ goto out;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+ if (std->urb == urb)
+ qset_free_std(whc, std);
+ else
+ std->qtd = NULL; /* so this std is re-added when the qset is */
+ }
+
+ pzl_qset_remove(whc, qset);
+ wurb->status = status;
+ wurb->is_async = false;
+ queue_work(whc->workqueue, &wurb->dequeue_work);
+
+out:
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+ return ret;
+}
+
+/**
+ * pzl_qset_delete - delete a qset from the PZL
+ */
+void pzl_qset_delete(struct whc *whc, struct whc_qset *qset)
+{
+ qset->remove = 1;
+ queue_work(whc->workqueue, &whc->periodic_work);
+ qset_delete(whc, qset);
+}
+
+
+/**
+ * pzl_init - initialize the periodic zone list
+ * @whc: the WHCI host controller
+ */
+int pzl_init(struct whc *whc)
+{
+ int i;
+
+ whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16,
+ &whc->pz_list_dma, GFP_KERNEL);
+ if (whc->pz_list == NULL)
+ return -ENOMEM;
+
+ /* Set T bit on all elements in PZL. */
+ for (i = 0; i < 16; i++)
+ whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
+
+ le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
+
+ return 0;
+}
+
+/**
+ * pzl_clean_up - free PZL resources
+ * @whc: the WHCI host controller
+ *
+ * The PZL is stopped and empty.
+ */
+void pzl_clean_up(struct whc *whc)
+{
+ if (whc->pz_list)
+ dma_free_coherent(&whc->umc->dev, sizeof(u64) * 16, whc->pz_list,
+ whc->pz_list_dma);
+}
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
new file mode 100644
index 00000000000..0420037d2e1
--- /dev/null
+++ b/drivers/usb/host/whci/qset.c
@@ -0,0 +1,567 @@
+/*
+ * Wireless Host Controller (WHC) qset management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/uwb/umc.h>
+#include <linux/usb.h>
+
+#include "../../wusbcore/wusbhc.h"
+
+#include "whcd.h"
+
+void dump_qset(struct whc_qset *qset, struct device *dev)
+{
+ struct whc_std *std;
+ struct urb *urb = NULL;
+ int i;
+
+ dev_dbg(dev, "qset %08x\n", (u32)qset->qset_dma);
+ dev_dbg(dev, " -> %08x\n", (u32)qset->qh.link);
+ dev_dbg(dev, " info: %08x %08x %08x\n",
+ qset->qh.info1, qset->qh.info2, qset->qh.info3);
+ dev_dbg(dev, " sts: %04x errs: %d\n", qset->qh.status, qset->qh.err_count);
+ dev_dbg(dev, " TD: sts: %08x opts: %08x\n",
+ qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options);
+
+ for (i = 0; i < WHCI_QSET_TD_MAX; i++) {
+ dev_dbg(dev, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n",
+ i == qset->td_start ? 'S' : ' ',
+ i == qset->td_end ? 'E' : ' ',
+ i, qset->qtd[i].status, qset->qtd[i].options,
+ (u32)qset->qtd[i].page_list_ptr);
+ }
+ dev_dbg(dev, " ntds: %d\n", qset->ntds);
+ list_for_each_entry(std, &qset->stds, list_node) {
+ if (urb != std->urb) {
+ urb = std->urb;
+ dev_dbg(dev, " urb %p transferred: %d bytes\n", urb,
+ urb->actual_length);
+ }
+ if (std->qtd)
+ dev_dbg(dev, " sTD[%td]: %zu bytes @ %08x\n",
+ std->qtd - &qset->qtd[0],
+ std->len, std->num_pointers ?
+ (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
+ else
+ dev_dbg(dev, " sTD[-]: %zd bytes @ %08x\n",
+ std->len, std->num_pointers ?
+ (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
+ }
+}
+
+struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags)
+{
+ struct whc_qset *qset;
+ dma_addr_t dma;
+
+ qset = dma_pool_alloc(whc->qset_pool, mem_flags, &dma);
+ if (qset == NULL)
+ return NULL;
+ memset(qset, 0, sizeof(struct whc_qset));
+
+ qset->qset_dma = dma;
+ qset->whc = whc;
+
+ INIT_LIST_HEAD(&qset->list_node);
+ INIT_LIST_HEAD(&qset->stds);
+
+ return qset;
+}
+
+/**
+ * qset_fill_qh - fill the static endpoint state in a qset's QHead
+ * @qset: the qset whose QH needs initializing with static endpoint
+ * state
+ * @urb: an urb for a transfer to this endpoint
+ */
+static void qset_fill_qh(struct whc_qset *qset, struct urb *urb)
+{
+ struct usb_device *usb_dev = urb->dev;
+ struct usb_wireless_ep_comp_descriptor *epcd;
+ bool is_out;
+
+ is_out = usb_pipeout(urb->pipe);
+
+ epcd = (struct usb_wireless_ep_comp_descriptor *)qset->ep->extra;
+
+ if (epcd) {
+ qset->max_seq = epcd->bMaxSequence;
+ qset->max_burst = epcd->bMaxBurst;
+ } else {
+ qset->max_seq = 2;
+ qset->max_burst = 1;
+ }
+
+ qset->qh.info1 = cpu_to_le32(
+ QH_INFO1_EP(usb_pipeendpoint(urb->pipe))
+ | (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN)
+ | usb_pipe_to_qh_type(urb->pipe)
+ | QH_INFO1_DEV_INFO_IDX(wusb_port_no_to_idx(usb_dev->portnum))
+ | QH_INFO1_MAX_PKT_LEN(usb_maxpacket(urb->dev, urb->pipe, is_out))
+ );
+ qset->qh.info2 = cpu_to_le32(
+ QH_INFO2_BURST(qset->max_burst)
+ | QH_INFO2_DBP(0)
+ | QH_INFO2_MAX_COUNT(3)
+ | QH_INFO2_MAX_RETRY(3)
+ | QH_INFO2_MAX_SEQ(qset->max_seq - 1)
+ );
+ /* FIXME: where can we obtain these Tx parameters from? Why
+ * doesn't the chip know what Tx power to use? It knows the Rx
+ * strength and can presumably guess the Tx power required
+ * from that? */
+ qset->qh.info3 = cpu_to_le32(
+ QH_INFO3_TX_RATE_53_3
+ | QH_INFO3_TX_PWR(0) /* 0 == max power */
+ );
+}
+
+/**
+ * qset_clear - clear fields in a qset so it may be reinserted into a
+ * schedule
+ */
+void qset_clear(struct whc *whc, struct whc_qset *qset)
+{
+ qset->td_start = qset->td_end = qset->ntds = 0;
+ qset->remove = 0;
+
+ qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T);
+ qset->qh.status = cpu_to_le16(QH_STATUS_ICUR(qset->td_start));
+ qset->qh.err_count = 0;
+ qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
+ qset->qh.scratch[0] = 0;
+ qset->qh.scratch[1] = 0;
+ qset->qh.scratch[2] = 0;
+
+ memset(&qset->qh.overlay, 0, sizeof(qset->qh.overlay));
+
+ init_completion(&qset->remove_complete);
+}
+
+/**
+ * get_qset - get the qset for an async endpoint
+ *
+ * A new qset is created if one does not already exist.
+ */
+struct whc_qset *get_qset(struct whc *whc, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct whc_qset *qset;
+
+ qset = urb->ep->hcpriv;
+ if (qset == NULL) {
+ qset = qset_alloc(whc, mem_flags);
+ if (qset == NULL)
+ return NULL;
+
+ qset->ep = urb->ep;
+ urb->ep->hcpriv = qset;
+ qset_fill_qh(qset, urb);
+ }
+ return qset;
+}
+
+void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
+{
+ list_del_init(&qset->list_node);
+ complete(&qset->remove_complete);
+}
+
+/**
+ * qset_add_qtds - add qTDs for an URB to a qset
+ *
+ * Returns true if the list (ASL/PZL) must be updated because (for a
+ * WHCI 0.95 controller) an activated qTD was pointed to be iCur.
+ */
+enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset)
+{
+ struct whc_std *std;
+ enum whc_update update = 0;
+
+ list_for_each_entry(std, &qset->stds, list_node) {
+ struct whc_qtd *qtd;
+ uint32_t status;
+
+ if (qset->ntds >= WHCI_QSET_TD_MAX
+ || (qset->pause_after_urb && std->urb != qset->pause_after_urb))
+ break;
+
+ if (std->qtd)
+ continue; /* already has a qTD */
+
+ qtd = std->qtd = &qset->qtd[qset->td_end];
+
+ /* Fill in setup bytes for control transfers. */
+ if (usb_pipecontrol(std->urb->pipe))
+ memcpy(qtd->setup, std->urb->setup_packet, 8);
+
+ status = QTD_STS_ACTIVE | QTD_STS_LEN(std->len);
+
+ if (whc_std_last(std) && usb_pipeout(std->urb->pipe))
+ status |= QTD_STS_LAST_PKT;
+
+ /*
+ * For an IN transfer the iAlt field should be set so
+ * the h/w will automatically advance to the next
+ * transfer. However, if there are 8 or more TDs
+ * remaining in this transfer then iAlt cannot be set
+ * as it could point to somewhere in this transfer.
+ */
+ if (std->ntds_remaining < WHCI_QSET_TD_MAX) {
+ int ialt;
+ ialt = (qset->td_end + std->ntds_remaining) % WHCI_QSET_TD_MAX;
+ status |= QTD_STS_IALT(ialt);
+ } else if (usb_pipein(std->urb->pipe))
+ qset->pause_after_urb = std->urb;
+
+ if (std->num_pointers)
+ qtd->options = cpu_to_le32(QTD_OPT_IOC);
+ else
+ qtd->options = cpu_to_le32(QTD_OPT_IOC | QTD_OPT_SMALL);
+ qtd->page_list_ptr = cpu_to_le64(std->dma_addr);
+
+ qtd->status = cpu_to_le32(status);
+
+ if (QH_STATUS_TO_ICUR(qset->qh.status) == qset->td_end)
+ update = WHC_UPDATE_UPDATED;
+
+ if (++qset->td_end >= WHCI_QSET_TD_MAX)
+ qset->td_end = 0;
+ qset->ntds++;
+ }
+
+ return update;
+}
+
+/**
+ * qset_remove_qtd - remove the first qTD from a qset.
+ *
+ * The qTD might be still active (if it's part of a IN URB that
+ * resulted in a short read) so ensure it's deactivated.
+ */
+static void qset_remove_qtd(struct whc *whc, struct whc_qset *qset)
+{
+ qset->qtd[qset->td_start].status = 0;
+
+ if (++qset->td_start >= WHCI_QSET_TD_MAX)
+ qset->td_start = 0;
+ qset->ntds--;
+}
+
+/**
+ * qset_free_std - remove an sTD and free it.
+ * @whc: the WHCI host controller
+ * @std: the sTD to remove and free.
+ */
+void qset_free_std(struct whc *whc, struct whc_std *std)
+{
+ list_del(&std->list_node);
+ if (std->num_pointers) {
+ dma_unmap_single(whc->wusbhc.dev, std->dma_addr,
+ std->num_pointers * sizeof(struct whc_page_list_entry),
+ DMA_TO_DEVICE);
+ kfree(std->pl_virt);
+ }
+
+ kfree(std);
+}
+
+/**
+ * qset_remove_qtds - remove an URB's qTDs (and sTDs).
+ */
+static void qset_remove_qtds(struct whc *whc, struct whc_qset *qset,
+ struct urb *urb)
+{
+ struct whc_std *std, *t;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+ if (std->urb != urb)
+ break;
+ if (std->qtd != NULL)
+ qset_remove_qtd(whc, qset);
+ qset_free_std(whc, std);
+ }
+}
+
+/**
+ * qset_free_stds - free any remaining sTDs for an URB.
+ */
+static void qset_free_stds(struct whc_qset *qset, struct urb *urb)
+{
+ struct whc_std *std, *t;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+ if (std->urb == urb)
+ qset_free_std(qset->whc, std);
+ }
+}
+
+static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_flags)
+{
+ dma_addr_t dma_addr = std->dma_addr;
+ dma_addr_t sp, ep;
+ size_t std_len = std->len;
+ size_t pl_len;
+ int p;
+
+ sp = ALIGN(dma_addr, WHCI_PAGE_SIZE);
+ ep = dma_addr + std_len;
+ std->num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
+
+ pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
+ std->pl_virt = kmalloc(pl_len, mem_flags);
+ if (std->pl_virt == NULL)
+ return -ENOMEM;
+ std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE);
+
+ for (p = 0; p < std->num_pointers; p++) {
+ std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
+ dma_addr = ALIGN(dma_addr + WHCI_PAGE_SIZE, WHCI_PAGE_SIZE);
+ }
+
+ return 0;
+}
+
+/**
+ * urb_dequeue_work - executes asl/pzl update and gives back the urb to the system.
+ */
+static void urb_dequeue_work(struct work_struct *work)
+{
+ struct whc_urb *wurb = container_of(work, struct whc_urb, dequeue_work);
+ struct whc_qset *qset = wurb->qset;
+ struct whc *whc = qset->whc;
+ unsigned long flags;
+
+ if (wurb->is_async == true)
+ asl_update(whc, WUSBCMD_ASYNC_UPDATED
+ | WUSBCMD_ASYNC_SYNCED_DB
+ | WUSBCMD_ASYNC_QSET_RM);
+ else
+ pzl_update(whc, WUSBCMD_PERIODIC_UPDATED
+ | WUSBCMD_PERIODIC_SYNCED_DB
+ | WUSBCMD_PERIODIC_QSET_RM);
+
+ spin_lock_irqsave(&whc->lock, flags);
+ qset_remove_urb(whc, qset, wurb->urb, wurb->status);
+ spin_unlock_irqrestore(&whc->lock, flags);
+}
+
+/**
+ * qset_add_urb - add an urb to the qset's queue.
+ *
+ * The URB is chopped into sTDs, one for each qTD that will required.
+ * At least one qTD (and sTD) is required even if the transfer has no
+ * data (e.g., for some control transfers).
+ */
+int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct whc_urb *wurb;
+ int remaining = urb->transfer_buffer_length;
+ u64 transfer_dma = urb->transfer_dma;
+ int ntds_remaining;
+
+ ntds_remaining = DIV_ROUND_UP(remaining, QTD_MAX_XFER_SIZE);
+ if (ntds_remaining == 0)
+ ntds_remaining = 1;
+
+ wurb = kzalloc(sizeof(struct whc_urb), mem_flags);
+ if (wurb == NULL)
+ goto err_no_mem;
+ urb->hcpriv = wurb;
+ wurb->qset = qset;
+ wurb->urb = urb;
+ INIT_WORK(&wurb->dequeue_work, urb_dequeue_work);
+
+ while (ntds_remaining) {
+ struct whc_std *std;
+ size_t std_len;
+
+ std = kmalloc(sizeof(struct whc_std), mem_flags);
+ if (std == NULL)
+ goto err_no_mem;
+
+ std_len = remaining;
+ if (std_len > QTD_MAX_XFER_SIZE)
+ std_len = QTD_MAX_XFER_SIZE;
+
+ std->urb = urb;
+ std->dma_addr = transfer_dma;
+ std->len = std_len;
+ std->ntds_remaining = ntds_remaining;
+ std->qtd = NULL;
+
+ INIT_LIST_HEAD(&std->list_node);
+ list_add_tail(&std->list_node, &qset->stds);
+
+ if (std_len > WHCI_PAGE_SIZE) {
+ if (qset_fill_page_list(whc, std, mem_flags) < 0)
+ goto err_no_mem;
+ } else
+ std->num_pointers = 0;
+
+ ntds_remaining--;
+ remaining -= std_len;
+ transfer_dma += std_len;
+ }
+
+ return 0;
+
+err_no_mem:
+ qset_free_stds(qset, urb);
+ return -ENOMEM;
+}
+
+/**
+ * qset_remove_urb - remove an URB from the urb queue.
+ *
+ * The URB is returned to the USB subsystem.
+ */
+void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
+ struct urb *urb, int status)
+{
+ struct wusbhc *wusbhc = &whc->wusbhc;
+ struct whc_urb *wurb = urb->hcpriv;
+
+ usb_hcd_unlink_urb_from_ep(&wusbhc->usb_hcd, urb);
+ /* Drop the lock as urb->complete() may enqueue another urb. */
+ spin_unlock(&whc->lock);
+ wusbhc_giveback_urb(wusbhc, urb, status);
+ spin_lock(&whc->lock);
+
+ kfree(wurb);
+}
+
+/**
+ * get_urb_status_from_qtd - get the completed urb status from qTD status
+ * @urb: completed urb
+ * @status: qTD status
+ */
+static int get_urb_status_from_qtd(struct urb *urb, u32 status)
+{
+ if (status & QTD_STS_HALTED) {
+ if (status & QTD_STS_DBE)
+ return usb_pipein(urb->pipe) ? -ENOSR : -ECOMM;
+ else if (status & QTD_STS_BABBLE)
+ return -EOVERFLOW;
+ else if (status & QTD_STS_RCE)
+ return -ETIME;
+ return -EPIPE;
+ }
+ if (usb_pipein(urb->pipe)
+ && (urb->transfer_flags & URB_SHORT_NOT_OK)
+ && urb->actual_length < urb->transfer_buffer_length)
+ return -EREMOTEIO;
+ return 0;
+}
+
+/**
+ * process_inactive_qtd - process an inactive (but not halted) qTD.
+ *
+ * Update the urb with the transfer bytes from the qTD, if the urb is
+ * completely transfered or (in the case of an IN only) the LPF is
+ * set, then the transfer is complete and the urb should be returned
+ * to the system.
+ */
+void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
+ struct whc_qtd *qtd)
+{
+ struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
+ struct urb *urb = std->urb;
+ uint32_t status;
+ bool complete;
+
+ status = le32_to_cpu(qtd->status);
+
+ urb->actual_length += std->len - QTD_STS_TO_LEN(status);
+
+ if (usb_pipein(urb->pipe) && (status & QTD_STS_LAST_PKT))
+ complete = true;
+ else
+ complete = whc_std_last(std);
+
+ qset_remove_qtd(whc, qset);
+ qset_free_std(whc, std);
+
+ /*
+ * Transfers for this URB are complete? Then return it to the
+ * USB subsystem.
+ */
+ if (complete) {
+ qset_remove_qtds(whc, qset, urb);
+ qset_remove_urb(whc, qset, urb, get_urb_status_from_qtd(urb, status));
+
+ /*
+ * If iAlt isn't valid then the hardware didn't
+ * advance iCur. Adjust the start and end pointers to
+ * match iCur.
+ */
+ if (!(status & QTD_STS_IALT_VALID))
+ qset->td_start = qset->td_end
+ = QH_STATUS_TO_ICUR(le16_to_cpu(qset->qh.status));
+ qset->pause_after_urb = NULL;
+ }
+}
+
+/**
+ * process_halted_qtd - process a qset with a halted qtd
+ *
+ * Remove all the qTDs for the failed URB and return the failed URB to
+ * the USB subsystem. Then remove all other qTDs so the qset can be
+ * removed.
+ *
+ * FIXME: this is the point where rate adaptation can be done. If a
+ * transfer failed because it exceeded the maximum number of retries
+ * then it could be reactivated with a slower rate without having to
+ * remove the qset.
+ */
+void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
+ struct whc_qtd *qtd)
+{
+ struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
+ struct urb *urb = std->urb;
+ int urb_status;
+
+ urb_status = get_urb_status_from_qtd(urb, le32_to_cpu(qtd->status));
+
+ qset_remove_qtds(whc, qset, urb);
+ qset_remove_urb(whc, qset, urb, urb_status);
+
+ list_for_each_entry(std, &qset->stds, list_node) {
+ if (qset->ntds == 0)
+ break;
+ qset_remove_qtd(whc, qset);
+ std->qtd = NULL;
+ }
+
+ qset->remove = 1;
+}
+
+void qset_free(struct whc *whc, struct whc_qset *qset)
+{
+ dma_pool_free(whc->qset_pool, qset, qset->qset_dma);
+}
+
+/**
+ * qset_delete - wait for a qset to be unused, then free it.
+ */
+void qset_delete(struct whc *whc, struct whc_qset *qset)
+{
+ wait_for_completion(&qset->remove_complete);
+ qset_free(whc, qset);
+}
diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h
new file mode 100644
index 00000000000..1d2a53bd39f
--- /dev/null
+++ b/drivers/usb/host/whci/whcd.h
@@ -0,0 +1,197 @@
+/*
+ * Wireless Host Controller (WHC) private header.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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 __WHCD_H
+#define __WHCD_H
+
+#include <linux/uwb/whci.h>
+#include <linux/workqueue.h>
+
+#include "whci-hc.h"
+
+/* Generic command timeout. */
+#define WHC_GENCMD_TIMEOUT_MS 100
+
+
+struct whc {
+ struct wusbhc wusbhc;
+ struct umc_dev *umc;
+
+ resource_size_t base_phys;
+ void __iomem *base;
+ int irq;
+
+ u8 n_devices;
+ u8 n_keys;
+ u8 n_mmc_ies;
+
+ u64 *pz_list;
+ struct dn_buf_entry *dn_buf;
+ struct di_buf_entry *di_buf;
+ dma_addr_t pz_list_dma;
+ dma_addr_t dn_buf_dma;
+ dma_addr_t di_buf_dma;
+
+ spinlock_t lock;
+ struct mutex mutex;
+
+ void * gen_cmd_buf;
+ dma_addr_t gen_cmd_buf_dma;
+ wait_queue_head_t cmd_wq;
+
+ struct workqueue_struct *workqueue;
+ struct work_struct dn_work;
+
+ struct dma_pool *qset_pool;
+
+ struct list_head async_list;
+ struct list_head async_removed_list;
+ wait_queue_head_t async_list_wq;
+ struct work_struct async_work;
+
+ struct list_head periodic_list[5];
+ struct list_head periodic_removed_list;
+ wait_queue_head_t periodic_list_wq;
+ struct work_struct periodic_work;
+};
+
+#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc))
+
+/**
+ * struct whc_std - a software TD.
+ * @urb: the URB this sTD is for.
+ * @offset: start of the URB's data for this TD.
+ * @len: the length of data in the associated TD.
+ * @ntds_remaining: number of TDs (starting from this one) in this transfer.
+ *
+ * Queued URBs may require more TDs than are available in a qset so we
+ * use a list of these "software TDs" (sTDs) to hold per-TD data.
+ */
+struct whc_std {
+ struct urb *urb;
+ size_t len;
+ int ntds_remaining;
+ struct whc_qtd *qtd;
+
+ struct list_head list_node;
+ int num_pointers;
+ dma_addr_t dma_addr;
+ struct whc_page_list_entry *pl_virt;
+};
+
+/**
+ * struct whc_urb - per URB host controller structure.
+ * @urb: the URB this struct is for.
+ * @qset: the qset associated to the URB.
+ * @dequeue_work: the work to remove the URB when dequeued.
+ * @is_async: the URB belongs to async sheduler or not.
+ * @status: the status to be returned when calling wusbhc_giveback_urb.
+ */
+struct whc_urb {
+ struct urb *urb;
+ struct whc_qset *qset;
+ struct work_struct dequeue_work;
+ bool is_async;
+ int status;
+};
+
+/**
+ * whc_std_last - is this sTD the URB's last?
+ * @std: the sTD to check.
+ */
+static inline bool whc_std_last(struct whc_std *std)
+{
+ return std->ntds_remaining <= 1;
+}
+
+enum whc_update {
+ WHC_UPDATE_ADDED = 0x01,
+ WHC_UPDATE_REMOVED = 0x02,
+ WHC_UPDATE_UPDATED = 0x04,
+};
+
+/* init.c */
+int whc_init(struct whc *whc);
+void whc_clean_up(struct whc *whc);
+
+/* hw.c */
+void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val);
+int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);
+
+/* wusb.c */
+int whc_wusbhc_start(struct wusbhc *wusbhc);
+void whc_wusbhc_stop(struct wusbhc *wusbhc);
+int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+ u8 handle, struct wuie_hdr *wuie);
+int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
+int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm);
+int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
+int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots);
+int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+ const void *ptk, size_t key_size);
+int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
+ const void *gtk, size_t key_size);
+int whc_set_cluster_id(struct whc *whc, u8 bcid);
+
+/* int.c */
+irqreturn_t whc_int_handler(struct usb_hcd *hcd);
+void whc_dn_work(struct work_struct *work);
+
+/* asl.c */
+void asl_start(struct whc *whc);
+void asl_stop(struct whc *whc);
+int asl_init(struct whc *whc);
+void asl_clean_up(struct whc *whc);
+int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
+int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
+void asl_qset_delete(struct whc *whc, struct whc_qset *qset);
+void scan_async_work(struct work_struct *work);
+
+/* pzl.c */
+int pzl_init(struct whc *whc);
+void pzl_clean_up(struct whc *whc);
+void pzl_start(struct whc *whc);
+void pzl_stop(struct whc *whc);
+int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
+int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
+void pzl_qset_delete(struct whc *whc, struct whc_qset *qset);
+void scan_periodic_work(struct work_struct *work);
+
+/* qset.c */
+struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags);
+void qset_free(struct whc *whc, struct whc_qset *qset);
+struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags);
+void qset_delete(struct whc *whc, struct whc_qset *qset);
+void qset_clear(struct whc *whc, struct whc_qset *qset);
+int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
+ gfp_t mem_flags);
+void qset_free_std(struct whc *whc, struct whc_std *std);
+void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
+ struct urb *urb, int status);
+void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
+ struct whc_qtd *qtd);
+void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
+ struct whc_qtd *qtd);
+enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset);
+void qset_remove_complete(struct whc *whc, struct whc_qset *qset);
+void dump_qset(struct whc_qset *qset, struct device *dev);
+void pzl_update(struct whc *whc, uint32_t wusbcmd);
+void asl_update(struct whc *whc, uint32_t wusbcmd);
+
+#endif /* #ifndef __WHCD_H */
diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h
new file mode 100644
index 00000000000..bff1eb7a35c
--- /dev/null
+++ b/drivers/usb/host/whci/whci-hc.h
@@ -0,0 +1,416 @@
+/*
+ * Wireless Host Controller (WHC) data structures.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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 _WHCI_WHCI_HC_H
+#define _WHCI_WHCI_HC_H
+
+#include <linux/list.h>
+
+/**
+ * WHCI_PAGE_SIZE - page size use by WHCI
+ *
+ * WHCI assumes that host system uses pages of 4096 octets.
+ */
+#define WHCI_PAGE_SIZE 4096
+
+
+/**
+ * QTD_MAX_TXFER_SIZE - max number of bytes to transfer with a single
+ * qtd.
+ *
+ * This is 2^20 - 1.
+ */
+#define QTD_MAX_XFER_SIZE 1048575
+
+
+/**
+ * struct whc_qtd - Queue Element Transfer Descriptors (qTD)
+ *
+ * This describes the data for a bulk, control or interrupt transfer.
+ *
+ * [WHCI] section 3.2.4
+ */
+struct whc_qtd {
+ __le32 status; /*< remaining transfer len and transfer status */
+ __le32 options;
+ __le64 page_list_ptr; /*< physical pointer to data buffer page list*/
+ __u8 setup[8]; /*< setup data for control transfers */
+} __attribute__((packed));
+
+#define QTD_STS_ACTIVE (1 << 31) /* enable execution of transaction */
+#define QTD_STS_HALTED (1 << 30) /* transfer halted */
+#define QTD_STS_DBE (1 << 29) /* data buffer error */
+#define QTD_STS_BABBLE (1 << 28) /* babble detected */
+#define QTD_STS_RCE (1 << 27) /* retry count exceeded */
+#define QTD_STS_LAST_PKT (1 << 26) /* set Last Packet Flag in WUSB header */
+#define QTD_STS_INACTIVE (1 << 25) /* queue set is marked inactive */
+#define QTD_STS_IALT_VALID (1 << 23) /* iAlt field is valid */
+#define QTD_STS_IALT(i) (QTD_STS_IALT_VALID | ((i) << 20)) /* iAlt field */
+#define QTD_STS_LEN(l) ((l) << 0) /* transfer length */
+#define QTD_STS_TO_LEN(s) ((s) & 0x000fffff)
+
+#define QTD_OPT_IOC (1 << 1) /* page_list_ptr points to buffer directly */
+#define QTD_OPT_SMALL (1 << 0) /* interrupt on complete */
+
+/**
+ * struct whc_itd - Isochronous Queue Element Transfer Descriptors (iTD)
+ *
+ * This describes the data and other parameters for an isochronous
+ * transfer.
+ *
+ * [WHCI] section 3.2.5
+ */
+struct whc_itd {
+ __le16 presentation_time; /*< presentation time for OUT transfers */
+ __u8 num_segments; /*< number of data segments in segment list */
+ __u8 status; /*< command execution status */
+ __le32 options; /*< misc transfer options */
+ __le64 page_list_ptr; /*< physical pointer to data buffer page list */
+ __le64 seg_list_ptr; /*< physical pointer to segment list */
+} __attribute__((packed));
+
+#define ITD_STS_ACTIVE (1 << 7) /* enable execution of transaction */
+#define ITD_STS_DBE (1 << 5) /* data buffer error */
+#define ITD_STS_BABBLE (1 << 4) /* babble detected */
+#define ITD_STS_INACTIVE (1 << 1) /* queue set is marked inactive */
+
+#define ITD_OPT_IOC (1 << 1) /* interrupt on complete */
+#define ITD_OPT_SMALL (1 << 0) /* page_list_ptr points to buffer directly */
+
+/**
+ * Page list entry.
+ *
+ * A TD's page list must contain sufficient page list entries for the
+ * total data length in the TD.
+ *
+ * [WHCI] section 3.2.4.3
+ */
+struct whc_page_list_entry {
+ __le64 buf_ptr; /*< physical pointer to buffer */
+} __attribute__((packed));
+
+/**
+ * struct whc_seg_list_entry - Segment list entry.
+ *
+ * Describes a portion of the data buffer described in the containing
+ * qTD's page list.
+ *
+ * seg_ptr = qtd->page_list_ptr[qtd->seg_list_ptr[seg].idx].buf_ptr
+ * + qtd->seg_list_ptr[seg].offset;
+ *
+ * Segments can't cross page boundries.
+ *
+ * [WHCI] section 3.2.5.5
+ */
+struct whc_seg_list_entry {
+ __le16 len; /*< segment length */
+ __u8 idx; /*< index into page list */
+ __u8 status; /*< segment status */
+ __le16 offset; /*< 12 bit offset into page */
+} __attribute__((packed));
+
+/**
+ * struct whc_qhead - endpoint and status information for a qset.
+ *
+ * [WHCI] section 3.2.6
+ */
+struct whc_qhead {
+ __le64 link; /*< next qset in list */
+ __le32 info1;
+ __le32 info2;
+ __le32 info3;
+ __le16 status;
+ __le16 err_count; /*< transaction error count */
+ __le32 cur_window;
+ __le32 scratch[3]; /*< h/w scratch area */
+ union {
+ struct whc_qtd qtd;
+ struct whc_itd itd;
+ } overlay;
+} __attribute__((packed));
+
+#define QH_LINK_PTR_MASK (~0x03Full)
+#define QH_LINK_PTR(ptr) ((ptr) & QH_LINK_PTR_MASK)
+#define QH_LINK_IQS (1 << 4) /* isochronous queue set */
+#define QH_LINK_NTDS(n) (((n) - 1) << 1) /* number of TDs in queue set */
+#define QH_LINK_T (1 << 0) /* last queue set in periodic schedule list */
+
+#define QH_INFO1_EP(e) ((e) << 0) /* endpoint number */
+#define QH_INFO1_DIR_IN (1 << 4) /* IN transfer */
+#define QH_INFO1_DIR_OUT (0 << 4) /* OUT transfer */
+#define QH_INFO1_TR_TYPE_CTRL (0x0 << 5) /* control transfer */
+#define QH_INFO1_TR_TYPE_ISOC (0x1 << 5) /* isochronous transfer */
+#define QH_INFO1_TR_TYPE_BULK (0x2 << 5) /* bulk transfer */
+#define QH_INFO1_TR_TYPE_INT (0x3 << 5) /* interrupt */
+#define QH_INFO1_TR_TYPE_LP_INT (0x7 << 5) /* low power interrupt */
+#define QH_INFO1_DEV_INFO_IDX(i) ((i) << 8) /* index into device info buffer */
+#define QH_INFO1_SET_INACTIVE (1 << 15) /* set inactive after transfer */
+#define QH_INFO1_MAX_PKT_LEN(l) ((l) << 16) /* maximum packet length */
+
+#define QH_INFO2_BURST(b) ((b) << 0) /* maximum burst length */
+#define QH_INFO2_DBP(p) ((p) << 5) /* data burst policy (see [WUSB] table 5-7) */
+#define QH_INFO2_MAX_COUNT(c) ((c) << 8) /* max isoc/int pkts per zone */
+#define QH_INFO2_RQS (1 << 15) /* reactivate queue set */
+#define QH_INFO2_MAX_RETRY(r) ((r) << 16) /* maximum transaction retries */
+#define QH_INFO2_MAX_SEQ(s) ((s) << 20) /* maximum sequence number */
+#define QH_INFO3_MAX_DELAY(d) ((d) << 0) /* maximum stream delay in 125 us units (isoc only) */
+#define QH_INFO3_INTERVAL(i) ((i) << 16) /* segment interval in 125 us units (isoc only) */
+
+#define QH_INFO3_TX_RATE_53_3 (0 << 24)
+#define QH_INFO3_TX_RATE_80 (1 << 24)
+#define QH_INFO3_TX_RATE_106_7 (2 << 24)
+#define QH_INFO3_TX_RATE_160 (3 << 24)
+#define QH_INFO3_TX_RATE_200 (4 << 24)
+#define QH_INFO3_TX_RATE_320 (5 << 24)
+#define QH_INFO3_TX_RATE_400 (6 << 24)
+#define QH_INFO3_TX_RATE_480 (7 << 24)
+#define QH_INFO3_TX_PWR(p) ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */
+
+#define QH_STATUS_FLOW_CTRL (1 << 15)
+#define QH_STATUS_ICUR(i) ((i) << 5)
+#define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7)
+
+/**
+ * usb_pipe_to_qh_type - USB core pipe type to QH transfer type
+ *
+ * Returns the QH type field for a USB core pipe type.
+ */
+static inline unsigned usb_pipe_to_qh_type(unsigned pipe)
+{
+ static const unsigned type[] = {
+ [PIPE_ISOCHRONOUS] = QH_INFO1_TR_TYPE_ISOC,
+ [PIPE_INTERRUPT] = QH_INFO1_TR_TYPE_INT,
+ [PIPE_CONTROL] = QH_INFO1_TR_TYPE_CTRL,
+ [PIPE_BULK] = QH_INFO1_TR_TYPE_BULK,
+ };
+ return type[usb_pipetype(pipe)];
+}
+
+/**
+ * Maxiumum number of TDs in a qset.
+ */
+#define WHCI_QSET_TD_MAX 8
+
+/**
+ * struct whc_qset - WUSB data transfers to a specific endpoint
+ * @qh: the QHead of this qset
+ * @qtd: up to 8 qTDs (for qsets for control, bulk and interrupt
+ * transfers)
+ * @itd: up to 8 iTDs (for qsets for isochronous transfers)
+ * @qset_dma: DMA address for this qset
+ * @whc: WHCI HC this qset is for
+ * @ep: endpoint
+ * @stds: list of sTDs queued to this qset
+ * @ntds: number of qTDs queued (not necessarily the same as nTDs
+ * field in the QH)
+ * @td_start: index of the first qTD in the list
+ * @td_end: index of next free qTD in the list (provided
+ * ntds < WHCI_QSET_TD_MAX)
+ *
+ * Queue Sets (qsets) are added to the asynchronous schedule list
+ * (ASL) or the periodic zone list (PZL).
+ *
+ * qsets may contain up to 8 TDs (either qTDs or iTDs as appropriate).
+ * Each TD may refer to at most 1 MiB of data. If a single transfer
+ * has > 8MiB of data, TDs can be reused as they are completed since
+ * the TD list is used as a circular buffer. Similarly, several
+ * (smaller) transfers may be queued in a qset.
+ *
+ * WHCI controllers may cache portions of the qsets in the ASL and
+ * PZL, requiring the WHCD to inform the WHC that the lists have been
+ * updated (fields changed or qsets inserted or removed). For safe
+ * insertion and removal of qsets from the lists the schedule must be
+ * stopped to avoid races in updating the QH link pointers.
+ *
+ * Since the HC is free to execute qsets in any order, all transfers
+ * to an endpoint should use the same qset to ensure transfers are
+ * executed in the order they're submitted.
+ *
+ * [WHCI] section 3.2.3
+ */
+struct whc_qset {
+ struct whc_qhead qh;
+ union {
+ struct whc_qtd qtd[WHCI_QSET_TD_MAX];
+ struct whc_itd itd[WHCI_QSET_TD_MAX];
+ };
+
+ /* private data for WHCD */
+ dma_addr_t qset_dma;
+ struct whc *whc;
+ struct usb_host_endpoint *ep;
+ struct list_head stds;
+ int ntds;
+ int td_start;
+ int td_end;
+ struct list_head list_node;
+ unsigned in_sw_list:1;
+ unsigned in_hw_list:1;
+ unsigned remove:1;
+ struct urb *pause_after_urb;
+ struct completion remove_complete;
+ int max_burst;
+ int max_seq;
+};
+
+static inline void whc_qset_set_link_ptr(u64 *ptr, u64 target)
+{
+ if (target)
+ *ptr = (*ptr & ~(QH_LINK_PTR_MASK | QH_LINK_T)) | QH_LINK_PTR(target);
+ else
+ *ptr = QH_LINK_T;
+}
+
+/**
+ * struct di_buf_entry - Device Information (DI) buffer entry.
+ *
+ * There's one of these per connected device.
+ */
+struct di_buf_entry {
+ __le32 availability_info[8]; /*< MAS availability information, one MAS per bit */
+ __le32 addr_sec_info; /*< addressing and security info */
+ __le32 reserved[7];
+} __attribute__((packed));
+
+#define WHC_DI_SECURE (1 << 31)
+#define WHC_DI_DISABLE (1 << 30)
+#define WHC_DI_KEY_IDX(k) ((k) << 8)
+#define WHC_DI_KEY_IDX_MASK 0x0000ff00
+#define WHC_DI_DEV_ADDR(a) ((a) << 0)
+#define WHC_DI_DEV_ADDR_MASK 0x000000ff
+
+/**
+ * struct dn_buf_entry - Device Notification (DN) buffer entry.
+ *
+ * [WHCI] section 3.2.8
+ */
+struct dn_buf_entry {
+ __u8 msg_size; /*< number of octets of valid DN data */
+ __u8 reserved1;
+ __u8 src_addr; /*< source address */
+ __u8 status; /*< buffer entry status */
+ __le32 tkid; /*< TKID for source device, valid if secure bit is set */
+ __u8 dn_data[56]; /*< up to 56 octets of DN data */
+} __attribute__((packed));
+
+#define WHC_DN_STATUS_VALID (1 << 7) /* buffer entry is valid */
+#define WHC_DN_STATUS_SECURE (1 << 6) /* notification received using secure frame */
+
+#define WHC_N_DN_ENTRIES (4096 / sizeof(struct dn_buf_entry))
+
+/* The Add MMC IE WUSB Generic Command may take up to 256 bytes of
+ data. [WHCI] section 2.4.7. */
+#define WHC_GEN_CMD_DATA_LEN 256
+
+/*
+ * HC registers.
+ *
+ * [WHCI] section 2.4
+ */
+
+#define WHCIVERSION 0x00
+
+#define WHCSPARAMS 0x04
+# define WHCSPARAMS_TO_N_MMC_IES(p) (((p) >> 16) & 0xff)
+# define WHCSPARAMS_TO_N_KEYS(p) (((p) >> 8) & 0xff)
+# define WHCSPARAMS_TO_N_DEVICES(p) (((p) >> 0) & 0x7f)
+
+#define WUSBCMD 0x08
+# define WUSBCMD_BCID(b) ((b) << 16)
+# define WUSBCMD_BCID_MASK (0xff << 16)
+# define WUSBCMD_ASYNC_QSET_RM (1 << 12)
+# define WUSBCMD_PERIODIC_QSET_RM (1 << 11)
+# define WUSBCMD_WUSBSI(s) ((s) << 8)
+# define WUSBCMD_WUSBSI_MASK (0x7 << 8)
+# define WUSBCMD_ASYNC_SYNCED_DB (1 << 7)
+# define WUSBCMD_PERIODIC_SYNCED_DB (1 << 6)
+# define WUSBCMD_ASYNC_UPDATED (1 << 5)
+# define WUSBCMD_PERIODIC_UPDATED (1 << 4)
+# define WUSBCMD_ASYNC_EN (1 << 3)
+# define WUSBCMD_PERIODIC_EN (1 << 2)
+# define WUSBCMD_WHCRESET (1 << 1)
+# define WUSBCMD_RUN (1 << 0)
+
+#define WUSBSTS 0x0c
+# define WUSBSTS_ASYNC_SCHED (1 << 15)
+# define WUSBSTS_PERIODIC_SCHED (1 << 14)
+# define WUSBSTS_DNTS_SCHED (1 << 13)
+# define WUSBSTS_HCHALTED (1 << 12)
+# define WUSBSTS_GEN_CMD_DONE (1 << 9)
+# define WUSBSTS_CHAN_TIME_ROLLOVER (1 << 8)
+# define WUSBSTS_DNTS_OVERFLOW (1 << 7)
+# define WUSBSTS_BPST_ADJUSTMENT_CHANGED (1 << 6)
+# define WUSBSTS_HOST_ERR (1 << 5)
+# define WUSBSTS_ASYNC_SCHED_SYNCED (1 << 4)
+# define WUSBSTS_PERIODIC_SCHED_SYNCED (1 << 3)
+# define WUSBSTS_DNTS_INT (1 << 2)
+# define WUSBSTS_ERR_INT (1 << 1)
+# define WUSBSTS_INT (1 << 0)
+# define WUSBSTS_INT_MASK 0x3ff
+
+#define WUSBINTR 0x10
+# define WUSBINTR_GEN_CMD_DONE (1 << 9)
+# define WUSBINTR_CHAN_TIME_ROLLOVER (1 << 8)
+# define WUSBINTR_DNTS_OVERFLOW (1 << 7)
+# define WUSBINTR_BPST_ADJUSTMENT_CHANGED (1 << 6)
+# define WUSBINTR_HOST_ERR (1 << 5)
+# define WUSBINTR_ASYNC_SCHED_SYNCED (1 << 4)
+# define WUSBINTR_PERIODIC_SCHED_SYNCED (1 << 3)
+# define WUSBINTR_DNTS_INT (1 << 2)
+# define WUSBINTR_ERR_INT (1 << 1)
+# define WUSBINTR_INT (1 << 0)
+# define WUSBINTR_ALL 0x3ff
+
+#define WUSBGENCMDSTS 0x14
+# define WUSBGENCMDSTS_ACTIVE (1 << 31)
+# define WUSBGENCMDSTS_ERROR (1 << 24)
+# define WUSBGENCMDSTS_IOC (1 << 23)
+# define WUSBGENCMDSTS_MMCIE_ADD 0x01
+# define WUSBGENCMDSTS_MMCIE_RM 0x02
+# define WUSBGENCMDSTS_SET_MAS 0x03
+# define WUSBGENCMDSTS_CHAN_STOP 0x04
+# define WUSBGENCMDSTS_RWP_EN 0x05
+
+#define WUSBGENCMDPARAMS 0x18
+#define WUSBGENADDR 0x20
+#define WUSBASYNCLISTADDR 0x28
+#define WUSBDNTSBUFADDR 0x30
+#define WUSBDEVICEINFOADDR 0x38
+
+#define WUSBSETSECKEYCMD 0x40
+# define WUSBSETSECKEYCMD_SET (1 << 31)
+# define WUSBSETSECKEYCMD_ERASE (1 << 30)
+# define WUSBSETSECKEYCMD_GTK (1 << 8)
+# define WUSBSETSECKEYCMD_IDX(i) ((i) << 0)
+
+#define WUSBTKID 0x44
+#define WUSBSECKEY 0x48
+#define WUSBPERIODICLISTBASE 0x58
+#define WUSBMASINDEX 0x60
+
+#define WUSBDNTSCTRL 0x64
+# define WUSBDNTSCTRL_ACTIVE (1 << 31)
+# define WUSBDNTSCTRL_INTERVAL(i) ((i) << 8)
+# define WUSBDNTSCTRL_SLOTS(s) ((s) << 0)
+
+#define WUSBTIME 0x68
+#define WUSBBPST 0x6c
+#define WUSBDIBUPDATED 0x70
+
+#endif /* #ifndef _WHCI_WHCI_HC_H */
diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c
new file mode 100644
index 00000000000..66e4ddcd961
--- /dev/null
+++ b/drivers/usb/host/whci/wusb.c
@@ -0,0 +1,241 @@
+/*
+ * Wireless Host Controller (WHC) WUSB operations.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/uwb/umc.h>
+#define D_LOCAL 1
+#include <linux/uwb/debug.h>
+
+#include "../../wusbcore/wusbhc.h"
+
+#include "whcd.h"
+
+#if D_LOCAL >= 1
+static void dump_di(struct whc *whc, int idx)
+{
+ struct di_buf_entry *di = &whc->di_buf[idx];
+ struct device *dev = &whc->umc->dev;
+ char buf[128];
+
+ bitmap_scnprintf(buf, sizeof(buf), (unsigned long *)di->availability_info, UWB_NUM_MAS);
+
+ d_printf(1, dev, "DI[%d]\n", idx);
+ d_printf(1, dev, " availability: %s\n", buf);
+ d_printf(1, dev, " %c%c key idx: %d dev addr: %d\n",
+ (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
+ (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
+ (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
+ (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
+}
+#else
+static inline void dump_di(struct whc *whc, int idx)
+{
+}
+#endif
+
+static int whc_update_di(struct whc *whc, int idx)
+{
+ int offset = idx / 32;
+ u32 bit = 1 << (idx % 32);
+
+ dump_di(whc, idx);
+
+ le_writel(bit, whc->base + WUSBDIBUPDATED + offset);
+
+ return whci_wait_for(&whc->umc->dev,
+ whc->base + WUSBDIBUPDATED + offset, bit, 0,
+ 100, "DI update");
+}
+
+/*
+ * WHCI starts and stops MMCs based on there being a valid GTK so
+ * these need only start/stop the asynchronous and periodic schedules.
+ */
+
+int whc_wusbhc_start(struct wusbhc *wusbhc)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+
+ asl_start(whc);
+ pzl_start(whc);
+
+ return 0;
+}
+
+void whc_wusbhc_stop(struct wusbhc *wusbhc)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+
+ pzl_stop(whc);
+ asl_stop(whc);
+}
+
+int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+ u8 handle, struct wuie_hdr *wuie)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u32 params;
+
+ params = (interval << 24)
+ | (repeat_cnt << 16)
+ | (wuie->bLength << 8)
+ | handle;
+
+ return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength);
+}
+
+int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u32 params;
+
+ params = handle;
+
+ return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0);
+}
+
+int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+
+ if (stream_index >= 0)
+ whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index));
+
+ return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm));
+}
+
+int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ int idx = wusb_dev->port_idx;
+ struct di_buf_entry *di = &whc->di_buf[idx];
+ int ret;
+
+ mutex_lock(&whc->mutex);
+
+ uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability);
+ di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK);
+ di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr);
+
+ ret = whc_update_di(whc, idx);
+
+ mutex_unlock(&whc->mutex);
+
+ return ret;
+}
+
+/*
+ * Set the number of Device Notification Time Slots (DNTS) and enable
+ * device notifications.
+ */
+int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ u32 dntsctrl;
+
+ dntsctrl = WUSBDNTSCTRL_ACTIVE
+ | WUSBDNTSCTRL_INTERVAL(interval)
+ | WUSBDNTSCTRL_SLOTS(slots);
+
+ le_writel(dntsctrl, whc->base + WUSBDNTSCTRL);
+
+ return 0;
+}
+
+static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid,
+ const void *key, size_t key_size, bool is_gtk)
+{
+ uint32_t setkeycmd;
+ uint32_t seckey[4];
+ int i;
+ int ret;
+
+ memcpy(seckey, key, key_size);
+ setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index);
+ if (is_gtk)
+ setkeycmd |= WUSBSETSECKEYCMD_GTK;
+
+ le_writel(tkid, whc->base + WUSBTKID);
+ for (i = 0; i < 4; i++)
+ le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i);
+ le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD);
+
+ ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD,
+ WUSBSETSECKEYCMD_SET, 0, 100, "set key");
+
+ return ret;
+}
+
+/**
+ * whc_set_ptk - set the PTK to use for a device.
+ *
+ * The index into the key table for this PTK is the same as the
+ * device's port index.
+ */
+int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+ const void *ptk, size_t key_size)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ struct di_buf_entry *di = &whc->di_buf[port_idx];
+ int ret;
+
+ mutex_lock(&whc->mutex);
+
+ if (ptk) {
+ ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false);
+ if (ret)
+ goto out;
+
+ di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK;
+ di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx);
+ } else
+ di->addr_sec_info &= ~WHC_DI_SECURE;
+
+ ret = whc_update_di(whc, port_idx);
+out:
+ mutex_unlock(&whc->mutex);
+ return ret;
+}
+
+/**
+ * whc_set_gtk - set the GTK for subsequent broadcast packets
+ *
+ * The GTK is stored in the last entry in the key table (the previous
+ * N_DEVICES entries are for the per-device PTKs).
+ */
+int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
+ const void *gtk, size_t key_size)
+{
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ int ret;
+
+ mutex_lock(&whc->mutex);
+
+ ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true);
+
+ mutex_unlock(&whc->mutex);
+
+ return ret;
+}
+
+int whc_set_cluster_id(struct whc *whc, u8 bcid)
+{
+ whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid));
+ return 0;
+}
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 0fb114ca1eb..878c77ca086 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -355,13 +355,14 @@ static int mdc800_usb_waitForIRQ (int mode, int msec)
if (mdc800->camera_request_ready>0)
{
mdc800->camera_request_ready=0;
- err ("timeout waiting for camera.");
+ dev_err(&mdc800->dev->dev, "timeout waiting for camera.\n");
return -1;
}
if (mdc800->state == NOT_CONNECTED)
{
- warn ("Camera gets disconnected during waiting for irq.");
+ printk(KERN_WARNING "mdc800: Camera gets disconnected "
+ "during waiting for irq.\n");
mdc800->camera_request_ready=0;
return -2;
}
@@ -379,7 +380,8 @@ static void mdc800_usb_write_notify (struct urb *urb)
int status = urb->status;
if (status != 0)
- err ("writing command fails (status=%i)", status);
+ dev_err(&mdc800->dev->dev,
+ "writing command fails (status=%i)\n", status);
else
mdc800->state=READY;
mdc800->written = 1;
@@ -406,7 +408,8 @@ static void mdc800_usb_download_notify (struct urb *urb)
mdc800->state=READY;
}
} else {
- err ("request bytes fails (status:%i)", status);
+ dev_err(&mdc800->dev->dev,
+ "request bytes fails (status:%i)\n", status);
}
mdc800->downloaded = 1;
wake_up (&mdc800->download_wait);
@@ -443,13 +446,14 @@ static int mdc800_usb_probe (struct usb_interface *intf,
if (mdc800->dev != NULL)
{
- warn ("only one Mustek MDC800 is supported.");
+ dev_warn(&intf->dev, "only one Mustek MDC800 is supported.\n");
return -ENODEV;
}
if (dev->descriptor.bNumConfigurations != 1)
{
- err ("probe fails -> wrong Number of Configuration");
+ dev_err(&intf->dev,
+ "probe fails -> wrong Number of Configuration\n");
return -ENODEV;
}
intf_desc = intf->cur_altsetting;
@@ -461,7 +465,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
|| ( intf_desc->desc.bNumEndpoints != 4)
)
{
- err ("probe fails -> wrong Interface");
+ dev_err(&intf->dev, "probe fails -> wrong Interface\n");
return -ENODEV;
}
@@ -482,19 +486,19 @@ static int mdc800_usb_probe (struct usb_interface *intf,
}
if (mdc800->endpoint[i] == -1)
{
- err ("probe fails -> Wrong Endpoints.");
+ dev_err(&intf->dev, "probe fails -> Wrong Endpoints.\n");
return -ENODEV;
}
}
- info ("Found Mustek MDC800 on USB.");
+ dev_info(&intf->dev, "Found Mustek MDC800 on USB.\n");
mutex_lock(&mdc800->io_lock);
retval = usb_register_dev(intf, &mdc800_class);
if (retval) {
- err ("Not able to get a minor for this device.");
+ dev_err(&intf->dev, "Not able to get a minor for this device.\n");
return -ENODEV;
}
@@ -570,7 +574,7 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
mdc800->dev = NULL;
usb_set_intfdata(intf, NULL);
}
- info ("Mustek MDC800 disconnected from USB.");
+ dev_info(&intf->dev, "Mustek MDC800 disconnected from USB.\n");
}
@@ -644,7 +648,8 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
mdc800->irq_urb->dev = mdc800->dev;
retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL);
if (retval) {
- err ("request USB irq fails (submit_retval=%i).", retval);
+ dev_err(&mdc800->dev->dev,
+ "request USB irq fails (submit_retval=%i).\n", retval);
errn = -EIO;
goto error_out;
}
@@ -701,7 +706,8 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
}
if (mdc800->state == WORKING)
{
- warn ("Illegal State \"working\" reached during read ?!");
+ printk(KERN_WARNING "mdc800: Illegal State \"working\""
+ "reached during read ?!\n");
mutex_unlock(&mdc800->io_lock);
return -EBUSY;
}
@@ -733,7 +739,9 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
mdc800->download_urb->dev = mdc800->dev;
retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL);
if (retval) {
- err ("Can't submit download urb (retval=%i)",retval);
+ dev_err(&mdc800->dev->dev,
+ "Can't submit download urb "
+ "(retval=%i)\n", retval);
mutex_unlock(&mdc800->io_lock);
return len-left;
}
@@ -742,7 +750,10 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
mdc800->downloaded = 0;
if (mdc800->download_urb->status != 0)
{
- err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
+ dev_err(&mdc800->dev->dev,
+ "request download-bytes fails "
+ "(status=%i)\n",
+ mdc800->download_urb->status);
mutex_unlock(&mdc800->io_lock);
return len-left;
}
@@ -839,7 +850,8 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
{
- err ("Camera didn't get ready.\n");
+ dev_err(&mdc800->dev->dev,
+ "Camera didn't get ready.\n");
mutex_unlock(&mdc800->io_lock);
return -EIO;
}
@@ -851,7 +863,9 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
mdc800->write_urb->dev = mdc800->dev;
retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL);
if (retval) {
- err ("submitting write urb fails (retval=%i)", retval);
+ dev_err(&mdc800->dev->dev,
+ "submitting write urb fails "
+ "(retval=%i)\n", retval);
mutex_unlock(&mdc800->io_lock);
return -EIO;
}
@@ -870,7 +884,9 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
case 0x3e: /* Take shot in Fine Mode (WCam Mode) */
if (mdc800->pic_len < 0)
{
- err ("call 0x07 before 0x05,0x3e");
+ dev_err(&mdc800->dev->dev,
+ "call 0x07 before "
+ "0x05,0x3e\n");
mdc800->state=READY;
mutex_unlock(&mdc800->io_lock);
return -EIO;
@@ -890,7 +906,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
{
- err ("requesting answer from irq fails");
+ dev_err(&mdc800->dev->dev, "requesting answer from irq fails\n");
mutex_unlock(&mdc800->io_lock);
return -EIO;
}
@@ -918,7 +934,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
{
if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
{
- err ("Command Timeout.");
+ dev_err(&mdc800->dev->dev, "Command Timeout.\n");
mutex_unlock(&mdc800->io_lock);
return -EIO;
}
@@ -1018,7 +1034,8 @@ static int __init usb_mdc800_init (void)
if (retval)
goto cleanup_on_fail;
- info (DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
@@ -1028,7 +1045,7 @@ cleanup_on_fail:
if (mdc800 != NULL)
{
- err ("can't alloc memory!");
+ printk(KERN_ERR "mdc800: can't alloc memory!\n");
kfree(mdc800->download_urb_buffer);
kfree(mdc800->write_urb_buffer);
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 4ea50e0abcb..e463db5d818 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -42,6 +42,15 @@ config USB_ADUTUX
To compile this driver as a module, choose M here. The module
will be called adutux.
+config USB_SEVSEG
+ tristate "USB 7-Segment LED Display"
+ depends on USB
+ help
+ Say Y here if you have a USB 7-Segment Display by Delcom
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbsevseg.
+
config USB_RIO500
tristate "USB Diamond Rio500 support"
depends on USB
@@ -271,3 +280,18 @@ config USB_ISIGHTFW
The firmware for this driver must be extracted from the MacOS
driver beforehand. Tools for doing so are available at
http://bersace03.free.fr
+
+config USB_VST
+ tristate "USB VST driver"
+ depends on USB
+ help
+ This driver is intended for Vernier Software Technologies
+ bulk usb devices such as their Ocean-Optics spectrometers or
+ Labquest.
+ It is a bulk channel driver with configurable read and write
+ timeouts.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vstusb.
+
+
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 45b4e12afb0..1334f7bdd7b 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -26,6 +26,8 @@ obj-$(CONFIG_USB_RIO500) += rio500.o
obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
obj-$(CONFIG_USB_USS720) += uss720.o
+obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o
+obj-$(CONFIG_USB_VST) += vstusb.o
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 965f6eaea6a..7b6922e08ed 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -283,8 +283,8 @@ static int adu_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&adu_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d",
- __func__, subminor);
+ printk(KERN_ERR "adutux: %s - error, can't find device for "
+ "minor %d\n", __func__, subminor);
retval = -ENODEV;
goto exit_no_device;
}
@@ -416,7 +416,8 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d", retval);
+ printk(KERN_ERR "adutux: No device or device unplugged %d\n",
+ retval);
goto exit;
}
@@ -576,7 +577,8 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d", retval);
+ printk(KERN_ERR "adutux: No device or device unplugged %d\n",
+ retval);
goto exit;
}
@@ -645,7 +647,8 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
if (retval < 0) {
dev->out_urb_finished = 1;
- err("Couldn't submit interrupt_out_urb %d", retval);
+ dev_err(&dev->udev->dev, "Couldn't submit "
+ "interrupt_out_urb %d\n", retval);
goto exit;
}
@@ -890,13 +893,14 @@ static int __init adu_init(void)
/* register this driver with the USB subsystem */
result = usb_register(&adu_driver);
if (result < 0) {
- err("usb_register failed for the "__FILE__" driver. "
- "Error number %d", result);
+ printk(KERN_ERR "usb_register failed for the "__FILE__
+ " driver. Error number %d\n", result);
goto exit;
}
- info("adutux " DRIVER_DESC " " DRIVER_VERSION);
- info("adutux is an experimental driver. Use at your own risk");
+ printk(KERN_INFO "adutux " DRIVER_DESC " " DRIVER_VERSION "\n");
+ printk(KERN_INFO "adutux is an experimental driver. "
+ "Use at your own risk\n");
exit:
dbg(2," %s : leave, return value %d", __func__, result);
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index a076c24a312..1d8e39a557d 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -130,7 +130,8 @@ static void appledisplay_complete(struct urb *urb)
exit:
retval = usb_submit_urb(pdata->urb, GFP_ATOMIC);
if (retval) {
- err("%s - usb_submit_urb failed with result %d",
+ dev_err(&pdata->udev->dev,
+ "%s - usb_submit_urb failed with result %d\n",
__func__, retval);
}
}
@@ -220,7 +221,7 @@ static int appledisplay_probe(struct usb_interface *iface,
}
}
if (!int_in_endpointAddr) {
- err("Could not find int-in endpoint");
+ dev_err(&iface->dev, "Could not find int-in endpoint\n");
return -EIO;
}
@@ -228,7 +229,7 @@ static int appledisplay_probe(struct usb_interface *iface,
pdata = kzalloc(sizeof(struct appledisplay), GFP_KERNEL);
if (!pdata) {
retval = -ENOMEM;
- err("Out of memory");
+ dev_err(&iface->dev, "Out of memory\n");
goto error;
}
@@ -241,8 +242,8 @@ static int appledisplay_probe(struct usb_interface *iface,
pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL);
if (!pdata->msgdata) {
retval = -ENOMEM;
- err("appledisplay: Allocating buffer for control messages "
- "failed");
+ dev_err(&iface->dev,
+ "Allocating buffer for control messages failed\n");
goto error;
}
@@ -250,7 +251,7 @@ static int appledisplay_probe(struct usb_interface *iface,
pdata->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pdata->urb) {
retval = -ENOMEM;
- err("appledisplay: Allocating URB failed");
+ dev_err(&iface->dev, "Allocating URB failed\n");
goto error;
}
@@ -259,7 +260,7 @@ static int appledisplay_probe(struct usb_interface *iface,
GFP_KERNEL, &pdata->urb->transfer_dma);
if (!pdata->urbdata) {
retval = -ENOMEM;
- err("appledisplay: Allocating URB buffer failed");
+ dev_err(&iface->dev, "Allocating URB buffer failed\n");
goto error;
}
@@ -270,7 +271,7 @@ static int appledisplay_probe(struct usb_interface *iface,
pdata, 1);
if (usb_submit_urb(pdata->urb, GFP_KERNEL)) {
retval = -EIO;
- err("appledisplay: Submitting URB failed");
+ dev_err(&iface->dev, "Submitting URB failed\n");
goto error;
}
@@ -280,7 +281,7 @@ static int appledisplay_probe(struct usb_interface *iface,
pdata->bd = backlight_device_register(bl_name, NULL, pdata,
&appledisplay_bl_data);
if (IS_ERR(pdata->bd)) {
- err("appledisplay: Backlight registration failed");
+ dev_err(&iface->dev, "Backlight registration failed\n");
goto error;
}
@@ -291,7 +292,8 @@ static int appledisplay_probe(struct usb_interface *iface,
if (brightness < 0) {
retval = brightness;
- err("appledisplay: Error while getting initial brightness: %d", retval);
+ dev_err(&iface->dev,
+ "Error while getting initial brightness: %d\n", retval);
goto error;
}
@@ -314,7 +316,7 @@ error:
pdata->urbdata, pdata->urb->transfer_dma);
usb_free_urb(pdata->urb);
}
- if (pdata->bd)
+ if (pdata->bd && !IS_ERR(pdata->bd))
backlight_device_unregister(pdata->bd);
kfree(pdata->msgdata);
}
@@ -352,7 +354,7 @@ static int __init appledisplay_init(void)
{
wq = create_singlethread_workqueue("appledisplay");
if (!wq) {
- err("Could not create work queue\n");
+ printk(KERN_ERR "appledisplay: Could not create work queue\n");
return -ENOMEM;
}
diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
index 937940404b7..5720bfef6a3 100644
--- a/drivers/usb/misc/cypress_cy7c63.c
+++ b/drivers/usb/misc/cypress_cy7c63.c
@@ -278,9 +278,9 @@ static int __init cypress_init(void)
/* register this driver with the USB subsystem */
result = usb_register(&cypress_driver);
- if (result) {
- err("Function usb_register failed! Error number: %d\n", result);
- }
+ if (result)
+ printk(KERN_ERR KBUILD_MODNAME ": usb_register failed! "
+ "Error number: %d\n", result);
return result;
}
diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
index 1cd9e7eba93..4fb3c38b924 100644
--- a/drivers/usb/misc/cytherm.c
+++ b/drivers/usb/misc/cytherm.c
@@ -422,13 +422,14 @@ static int __init usb_cytherm_init(void)
int result;
result = usb_register(&cytherm_driver);
- if (result)
- {
- err("usb_register failed. Error number %d", result);
+ if (result) {
+ printk(KERN_ERR KBUILD_MODNAME ": usb_register failed! "
+ "Error number: %d\n", result);
return result;
}
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
}
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
index 4b994a0cd27..e762beb5f3c 100644
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -50,7 +50,7 @@ static int emi26_writememory (struct usb_device *dev, int address,
unsigned char *buffer = kmemdup(data, length, GFP_KERNEL);
if (!buffer) {
- err("emi26: kmalloc(%d) failed.", length);
+ dev_err(&dev->dev, "kmalloc(%d) failed.\n", length);
return -ENOMEM;
}
/* Note: usb_control_msg returns negative value on error or length of the
@@ -64,11 +64,11 @@ static int emi26_writememory (struct usb_device *dev, int address,
static int emi26_set_reset (struct usb_device *dev, unsigned char reset_bit)
{
int response;
- info("%s - %d", __func__, reset_bit);
+ dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit);
/* printk(KERN_DEBUG "%s - %d", __func__, reset_bit); */
response = emi26_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
if (response < 0) {
- err("emi26: set_reset (%d) failed", reset_bit);
+ dev_err(&dev->dev, "set_reset (%d) failed\n", reset_bit);
}
return response;
}
@@ -88,7 +88,8 @@ static int emi26_load_firmware (struct usb_device *dev)
buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
if (!buf) {
- err( "%s - error loading firmware: error = %d", __func__, -ENOMEM);
+ dev_err(&dev->dev, "%s - error loading firmware: error = %d\n",
+ __func__, -ENOMEM);
err = -ENOMEM;
goto wraperr;
}
@@ -106,14 +107,16 @@ static int emi26_load_firmware (struct usb_device *dev)
&dev->dev);
if (err) {
nofw:
- err( "%s - request_firmware() failed", __func__);
+ dev_err(&dev->dev, "%s - request_firmware() failed\n",
+ __func__);
goto wraperr;
}
/* Assert reset (stop the CPU in the EMI) */
err = emi26_set_reset(dev,1);
if (err < 0) {
- err( "%s - error loading firmware: error = %d", __func__, err);
+ dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
+ __func__, err);
goto wraperr;
}
@@ -254,7 +257,7 @@ static int emi26_probe(struct usb_interface *intf, const struct usb_device_id *i
{
struct usb_device *dev = interface_to_usbdev(intf);
- info("%s start", __func__);
+ dev_info(&intf->dev, "%s start\n", __func__);
emi26_load_firmware(dev);
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index 5d859ded5bb..602ee05ba9f 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -73,7 +73,7 @@ static int emi62_writememory(struct usb_device *dev, int address,
static int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit)
{
int response;
- info("%s - %d", __func__, reset_bit);
+ dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit);
response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
if (response < 0) {
@@ -271,7 +271,7 @@ static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *i
struct usb_device *dev = interface_to_usbdev(intf);
dev_dbg(&intf->dev, "emi62_probe\n");
- info("%s start", __func__);
+ dev_info(&intf->dev, "%s start\n", __func__);
emi62_load_firmware(dev);
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 97c28097153..79a7668ef26 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -698,7 +698,7 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
int retval = usb_bulk_msg(ftdi->udev,
usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, msecs_to_jiffies(50));
+ &packet_bytes, 50);
if (packet_bytes > 2) {
ftdi->bulk_in_left = packet_bytes - 2;
ftdi->bulk_in_last = 1;
@@ -960,7 +960,7 @@ static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi)
int retval = usb_bulk_msg(ftdi->udev,
usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, msecs_to_jiffies(500));
+ &packet_bytes, 500);
char diag[30 *3 + 4];
char *d = diag;
int m = packet_bytes;
@@ -1880,7 +1880,7 @@ static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi)
int retval = usb_bulk_msg(ftdi->udev,
usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, msecs_to_jiffies(100));
+ &packet_bytes, 100);
if (packet_bytes > 2) {
char diag[30 *3 + 4];
char *d = diag;
@@ -2067,7 +2067,7 @@ static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
usb_rcvbulkpipe(ftdi->udev,
ftdi->bulk_in_endpointAddr),
ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, msecs_to_jiffies(500));
+ &packet_bytes, 500);
if (packet_bytes > 2) {
char diag[30 *3 + 4];
char *d = diag;
@@ -2176,7 +2176,7 @@ static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi)
int retval = usb_bulk_msg(ftdi->udev,
usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, msecs_to_jiffies(1000));
+ &packet_bytes, 1000);
if (packet_bytes > 2) {
char diag[30 *3 + 4];
char *d = diag;
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 4bcf7fb4e5d..6da8887538c 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -403,14 +403,15 @@ static void idmouse_disconnect(struct usb_interface *interface)
mutex_unlock(&dev->lock);
}
- info("%s disconnected", DRIVER_DESC);
+ dev_info(&interface->dev, "disconnected\n");
}
static int __init usb_idmouse_init(void)
{
int result;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
/* register this driver with the USB subsystem */
result = usb_register(&idmouse_driver);
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 9370326a594..ab0f3226158 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -851,9 +851,8 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
dbg(2, "%s: enter", __func__);
- if (udev == NULL) {
- info ("udev is NULL.");
- }
+ if (udev == NULL)
+ dev_info(&interface->dev, "udev is NULL.\n");
/* allocate memory for our device state and initialize it */
@@ -954,7 +953,9 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
dev->minor = interface->minor;
/* let the user know what node this device is now attached to */
- info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor);
+ dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major "
+ "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE),
+ USB_MAJOR, dev->minor);
/* get the firmware version and log it */
result = usb_control_msg (udev,
@@ -971,10 +972,10 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
retval = result;
goto error;
}
- info("LEGO USB Tower firmware version is %d.%d build %d",
- get_version_reply.major,
- get_version_reply.minor,
- le16_to_cpu(get_version_reply.build_no));
+ dev_info(&interface->dev, "LEGO USB Tower firmware version is %d.%d "
+ "build %d\n", get_version_reply.major,
+ get_version_reply.minor,
+ le16_to_cpu(get_version_reply.build_no));
exit:
@@ -1021,7 +1022,8 @@ static void tower_disconnect (struct usb_interface *interface)
mutex_unlock(&dev->lock);
}
- info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
+ dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n",
+ (minor - LEGO_USB_TOWER_MINOR_BASE));
dbg(2, "%s: leave", __func__);
}
@@ -1046,7 +1048,8 @@ static int __init lego_usb_tower_init(void)
goto exit;
}
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
exit:
dbg(2, "%s: leave, return value %d", __func__, retval);
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 248a12aacef..deb95bb49fd 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -89,7 +89,7 @@ static int open_rio(struct inode *inode, struct file *file)
mutex_unlock(&(rio->lock));
- info("Rio opened.");
+ dev_info(&rio->rio_dev->dev, "Rio opened.\n");
return 0;
}
@@ -100,7 +100,7 @@ static int close_rio(struct inode *inode, struct file *file)
rio->isopen = 0;
- info("Rio closed.");
+ dev_info(&rio->rio_dev->dev, "Rio closed.\n");
return 0;
}
@@ -451,7 +451,7 @@ static int probe_rio(struct usb_interface *intf,
struct rio_usb_data *rio = &rio_instance;
int retval;
- info("USB Rio found at address %d", dev->devnum);
+ dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum);
retval = usb_register_dev(intf, &usb_rio_class);
if (retval) {
@@ -503,7 +503,7 @@ static void disconnect_rio(struct usb_interface *intf)
kfree(rio->ibuf);
kfree(rio->obuf);
- info("USB Rio disconnected.");
+ dev_info(&intf->dev, "USB Rio disconnected.\n");
rio->present = 0;
mutex_unlock(&(rio->lock));
@@ -531,7 +531,8 @@ static int __init usb_rio_init(void)
if (retval)
goto out;
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
out:
return retval;
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
index 03368edf3f2..2e14102955c 100644
--- a/drivers/usb/misc/trancevibrator.c
+++ b/drivers/usb/misc/trancevibrator.c
@@ -144,7 +144,8 @@ static int __init tv_init(void)
return retval;
}
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
}
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 2db4228fbb0..e0ff9ccd866 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -311,7 +311,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
dev->interface = interface;
if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) {
- warn(KERN_INFO "USBLCD model not supported.");
+ dev_warn(&interface->dev, "USBLCD model not supported.\n");
return -ENODEV;
}
@@ -359,12 +359,13 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
i = le16_to_cpu(dev->udev->descriptor.bcdDevice);
- info("USBLCD Version %1d%1d.%1d%1d found at address %d",
- (i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF),
- dev->udev->devnum);
+ dev_info(&interface->dev, "USBLCD Version %1d%1d.%1d%1d found "
+ "at address %d\n", (i & 0xF000)>>12, (i & 0xF00)>>8,
+ (i & 0xF0)>>4,(i & 0xF), dev->udev->devnum);
/* let the user know what node this device is now attached to */
- info("USB LCD device now attached to USBLCD-%d", interface->minor);
+ dev_info(&interface->dev, "USB LCD device now attached to USBLCD-%d\n",
+ interface->minor);
return 0;
error:
@@ -413,7 +414,7 @@ static void lcd_disconnect(struct usb_interface *interface)
/* decrement our usage count */
kref_put(&dev->kref, lcd_delete);
- info("USB LCD #%d now disconnected", minor);
+ dev_info(&interface->dev, "USB LCD #%d now disconnected\n", minor);
}
static struct usb_driver lcd_driver = {
diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c
new file mode 100644
index 00000000000..28a6a3a0953
--- /dev/null
+++ b/drivers/usb/misc/usbsevseg.c
@@ -0,0 +1,394 @@
+/*
+ * USB 7 Segment Driver
+ *
+ * Copyright (C) 2008 Harrison Metzger <harrisonmetz@gmail.com>
+ * Based on usbled.c by Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+
+
+#define DRIVER_AUTHOR "Harrison Metzger <harrisonmetz@gmail.com>"
+#define DRIVER_DESC "USB 7 Segment Driver"
+
+#define VENDOR_ID 0x0fc5
+#define PRODUCT_ID 0x1227
+#define MAXLEN 6
+
+/* table of devices that work with this driver */
+static struct usb_device_id id_table[] = {
+ { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/* the different text display modes the device is capable of */
+static char *display_textmodes[] = {"raw", "hex", "ascii", NULL};
+
+struct usb_sevsegdev {
+ struct usb_device *udev;
+
+ u8 powered;
+ u8 mode_msb;
+ u8 mode_lsb;
+ u8 decimals[MAXLEN];
+ u8 textmode;
+ u8 text[MAXLEN];
+ u16 textlength;
+};
+
+/* sysfs_streq can't replace this completely
+ * If the device was in hex mode, and the user wanted a 0,
+ * if str commands are used, we would assume the end of string
+ * so mem commands are used.
+ */
+inline size_t my_memlen(const char *buf, size_t count)
+{
+ if (count > 0 && buf[count-1] == '\n')
+ return count - 1;
+ else
+ return count;
+}
+
+static void update_display_powered(struct usb_sevsegdev *mydev)
+{
+ int rc;
+
+ rc = usb_control_msg(mydev->udev,
+ usb_sndctrlpipe(mydev->udev, 0),
+ 0x12,
+ 0x48,
+ (80 * 0x100) + 10, /* (power mode) */
+ (0x00 * 0x100) + (mydev->powered ? 1 : 0),
+ NULL,
+ 0,
+ 2000);
+ if (rc < 0)
+ dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc);
+}
+
+static void update_display_mode(struct usb_sevsegdev *mydev)
+{
+ int rc;
+
+ rc = usb_control_msg(mydev->udev,
+ usb_sndctrlpipe(mydev->udev, 0),
+ 0x12,
+ 0x48,
+ (82 * 0x100) + 10, /* (set mode) */
+ (mydev->mode_msb * 0x100) + mydev->mode_lsb,
+ NULL,
+ 0,
+ 2000);
+
+ if (rc < 0)
+ dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc);
+}
+
+static void update_display_visual(struct usb_sevsegdev *mydev)
+{
+ int rc;
+ int i;
+ unsigned char *buffer;
+ u8 decimals = 0;
+
+ buffer = kzalloc(MAXLEN, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&mydev->udev->dev, "out of memory\n");
+ return;
+ }
+
+ /* The device is right to left, where as you write left to right */
+ for (i = 0; i < mydev->textlength; i++)
+ buffer[i] = mydev->text[mydev->textlength-1-i];
+
+ rc = usb_control_msg(mydev->udev,
+ usb_sndctrlpipe(mydev->udev, 0),
+ 0x12,
+ 0x48,
+ (85 * 0x100) + 10, /* (write text) */
+ (0 * 0x100) + mydev->textmode, /* mode */
+ buffer,
+ mydev->textlength,
+ 2000);
+
+ if (rc < 0)
+ dev_dbg(&mydev->udev->dev, "write retval = %d\n", rc);
+
+ kfree(buffer);
+
+ /* The device is right to left, where as you write left to right */
+ for (i = 0; i < sizeof(mydev->decimals); i++)
+ decimals |= mydev->decimals[i] << i;
+
+ rc = usb_control_msg(mydev->udev,
+ usb_sndctrlpipe(mydev->udev, 0),
+ 0x12,
+ 0x48,
+ (86 * 0x100) + 10, /* (set decimal) */
+ (0 * 0x100) + decimals, /* decimals */
+ NULL,
+ 0,
+ 2000);
+
+ if (rc < 0)
+ dev_dbg(&mydev->udev->dev, "decimal retval = %d\n", rc);
+}
+
+#define MYDEV_ATTR_SIMPLE_UNSIGNED(name, update_fcn) \
+static ssize_t show_attr_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \
+ \
+ return sprintf(buf, "%u\n", mydev->name); \
+} \
+ \
+static ssize_t set_attr_##name(struct device *dev, \
+ struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \
+ \
+ mydev->name = simple_strtoul(buf, NULL, 10); \
+ update_fcn(mydev); \
+ \
+ return count; \
+} \
+static DEVICE_ATTR(name, S_IWUGO | S_IRUGO, show_attr_##name, set_attr_##name);
+
+static ssize_t show_attr_text(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
+
+ return snprintf(buf, mydev->textlength, "%s\n", mydev->text);
+}
+
+static ssize_t set_attr_text(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
+ size_t end = my_memlen(buf, count);
+
+ if (end > sizeof(mydev->text))
+ return -EINVAL;
+
+ memset(mydev->text, 0, sizeof(mydev->text));
+ mydev->textlength = end;
+
+ if (end > 0)
+ memcpy(mydev->text, buf, end);
+
+ update_display_visual(mydev);
+ return count;
+}
+
+static DEVICE_ATTR(text, S_IWUGO | S_IRUGO, show_attr_text, set_attr_text);
+
+static ssize_t show_attr_decimals(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
+ int i;
+ int pos;
+
+ for (i = 0; i < sizeof(mydev->decimals); i++) {
+ pos = sizeof(mydev->decimals) - 1 - i;
+ if (mydev->decimals[i] == 0)
+ buf[pos] = '0';
+ else if (mydev->decimals[i] == 1)
+ buf[pos] = '1';
+ else
+ buf[pos] = 'x';
+ }
+
+ buf[sizeof(mydev->decimals)] = '\n';
+ return sizeof(mydev->decimals) + 1;
+}
+
+static ssize_t set_attr_decimals(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
+ size_t end = my_memlen(buf, count);
+ int i;
+
+ if (end > sizeof(mydev->decimals))
+ return -EINVAL;
+
+ for (i = 0; i < end; i++)
+ if (buf[i] != '0' && buf[i] != '1')
+ return -EINVAL;
+
+ memset(mydev->decimals, 0, sizeof(mydev->decimals));
+ for (i = 0; i < end; i++)
+ if (buf[i] == '1')
+ mydev->decimals[end-1-i] = 1;
+
+ update_display_visual(mydev);
+
+ return count;
+}
+
+static DEVICE_ATTR(decimals, S_IWUGO | S_IRUGO,
+ show_attr_decimals, set_attr_decimals);
+
+static ssize_t show_attr_textmode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
+ int i;
+
+ buf[0] = 0;
+
+ for (i = 0; display_textmodes[i]; i++) {
+ if (mydev->textmode == i) {
+ strcat(buf, " [");
+ strcat(buf, display_textmodes[i]);
+ strcat(buf, "] ");
+ } else {
+ strcat(buf, " ");
+ strcat(buf, display_textmodes[i]);
+ strcat(buf, " ");
+ }
+ }
+ strcat(buf, "\n");
+
+
+ return strlen(buf);
+}
+
+static ssize_t set_attr_textmode(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
+ int i;
+
+ for (i = 0; display_textmodes[i]; i++) {
+ if (sysfs_streq(display_textmodes[i], buf)) {
+ mydev->textmode = i;
+ update_display_visual(mydev);
+ return count;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(textmode, S_IWUGO | S_IRUGO,
+ show_attr_textmode, set_attr_textmode);
+
+
+MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered);
+MYDEV_ATTR_SIMPLE_UNSIGNED(mode_msb, update_display_mode);
+MYDEV_ATTR_SIMPLE_UNSIGNED(mode_lsb, update_display_mode);
+
+static struct attribute *dev_attrs[] = {
+ &dev_attr_powered.attr,
+ &dev_attr_text.attr,
+ &dev_attr_textmode.attr,
+ &dev_attr_decimals.attr,
+ &dev_attr_mode_msb.attr,
+ &dev_attr_mode_lsb.attr,
+ NULL
+};
+
+static struct attribute_group dev_attr_grp = {
+ .attrs = dev_attrs,
+};
+
+static int sevseg_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct usb_sevsegdev *mydev = NULL;
+ int rc = -ENOMEM;
+
+ mydev = kzalloc(sizeof(struct usb_sevsegdev), GFP_KERNEL);
+ if (mydev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ goto error_mem;
+ }
+
+ mydev->udev = usb_get_dev(udev);
+ usb_set_intfdata(interface, mydev);
+
+ /*set defaults */
+ mydev->textmode = 0x02; /* ascii mode */
+ mydev->mode_msb = 0x06; /* 6 characters */
+ mydev->mode_lsb = 0x3f; /* scanmode for 6 chars */
+
+ rc = sysfs_create_group(&interface->dev.kobj, &dev_attr_grp);
+ if (rc)
+ goto error;
+
+ dev_info(&interface->dev, "USB 7 Segment device now attached\n");
+ return 0;
+
+error:
+ usb_set_intfdata(interface, NULL);
+ usb_put_dev(mydev->udev);
+ kfree(mydev);
+error_mem:
+ return rc;
+}
+
+static void sevseg_disconnect(struct usb_interface *interface)
+{
+ struct usb_sevsegdev *mydev;
+
+ mydev = usb_get_intfdata(interface);
+ sysfs_remove_group(&interface->dev.kobj, &dev_attr_grp);
+ usb_set_intfdata(interface, NULL);
+ usb_put_dev(mydev->udev);
+ kfree(mydev);
+ dev_info(&interface->dev, "USB 7 Segment now disconnected\n");
+}
+
+static struct usb_driver sevseg_driver = {
+ .name = "usbsevseg",
+ .probe = sevseg_probe,
+ .disconnect = sevseg_disconnect,
+ .id_table = id_table,
+};
+
+static int __init usb_sevseg_init(void)
+{
+ int rc = 0;
+
+ rc = usb_register(&sevseg_driver);
+ if (rc)
+ err("usb_register failed. Error number %d", rc);
+ return rc;
+}
+
+static void __exit usb_sevseg_exit(void)
+{
+ usb_deregister(&sevseg_driver);
+}
+
+module_init(usb_sevseg_init);
+module_exit(usb_sevseg_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index b358c4e1cf2..444c69c447b 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1561,8 +1561,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (code != USBTEST_REQUEST)
return -EOPNOTSUPP;
- if (param->iterations <= 0 || param->length < 0
- || param->sglen < 0 || param->vary < 0)
+ if (param->iterations <= 0)
return -EINVAL;
if (mutex_lock_interruptible(&dev->lock))
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index f1255b0a182..9a6c27a0179 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -228,11 +228,12 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha
ret = rq->urb->status;
*val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
if (ret)
- warn("get_1284_register: usb error %d", ret);
+ printk(KERN_WARNING "get_1284_register: "
+ "usb error %d\n", ret);
kref_put(&rq->ref_count, destroy_async);
return ret;
}
- warn("get_1284_register timeout");
+ printk(KERN_WARNING "get_1284_register timeout\n");
kill_all_async_requests_priv(priv);
return -EIO;
}
@@ -716,7 +717,7 @@ static int uss720_probe(struct usb_interface *intf,
spin_lock_init(&priv->asynclock);
INIT_LIST_HEAD(&priv->asynclist);
if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
- warn("could not register parport");
+ printk(KERN_WARNING "uss720: could not register parport\n");
goto probe_abort;
}
@@ -800,10 +801,14 @@ static int __init uss720_init(void)
if (retval)
goto out;
- info(DRIVER_VERSION ":" DRIVER_DESC);
- info("NOTE: this is a special purpose driver to allow nonstandard");
- info("protocols (eg. bitbang) over USS720 usb to parallel cables");
- info("If you just want to connect to a printer, use usblp instead");
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
+ printk(KERN_INFO KBUILD_MODNAME ": NOTE: this is a special purpose "
+ "driver to allow nonstandard\n");
+ printk(KERN_INFO KBUILD_MODNAME ": protocols (eg. bitbang) over "
+ "USS720 usb to parallel cables\n");
+ printk(KERN_INFO KBUILD_MODNAME ": If you just want to connect to a "
+ "printer, use usblp instead\n");
out:
return retval;
}
diff --git a/drivers/usb/misc/vstusb.c b/drivers/usb/misc/vstusb.c
new file mode 100644
index 00000000000..8648470c81c
--- /dev/null
+++ b/drivers/usb/misc/vstusb.c
@@ -0,0 +1,782 @@
+/*****************************************************************************
+ * File: drivers/usb/misc/vstusb.c
+ *
+ * Purpose: Support for the bulk USB Vernier Spectrophotometers
+ *
+ * Author: Johnnie Peters
+ * Axian Consulting
+ * Beaverton, OR, USA 97005
+ *
+ * Modified by: EQware Engineering, Inc.
+ * Oregon City, OR, USA 97045
+ *
+ * Copyright: 2007, 2008
+ * Vernier Software & Technology
+ * Beaverton, OR, USA 97005
+ *
+ * Web: www.vernier.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/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <linux/usb/vstusb.h>
+
+#define DRIVER_VERSION "VST USB Driver Version 1.5"
+#define DRIVER_DESC "Vernier Software Technology Bulk USB Driver"
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+ #define VSTUSB_MINOR_BASE 0
+#else
+ #define VSTUSB_MINOR_BASE 199
+#endif
+
+#define USB_VENDOR_OCEANOPTICS 0x2457
+#define USB_VENDOR_VERNIER 0x08F7 /* Vernier Software & Technology */
+
+#define USB_PRODUCT_USB2000 0x1002
+#define USB_PRODUCT_ADC1000_FW 0x1003 /* firmware download (renumerates) */
+#define USB_PRODUCT_ADC1000 0x1004
+#define USB_PRODUCT_HR2000_FW 0x1009 /* firmware download (renumerates) */
+#define USB_PRODUCT_HR2000 0x100A
+#define USB_PRODUCT_HR4000_FW 0x1011 /* firmware download (renumerates) */
+#define USB_PRODUCT_HR4000 0x1012
+#define USB_PRODUCT_USB650 0x1014 /* "Red Tide" */
+#define USB_PRODUCT_QE65000 0x1018
+#define USB_PRODUCT_USB4000 0x1022
+#define USB_PRODUCT_USB325 0x1024 /* "Vernier Spectrometer" */
+
+#define USB_PRODUCT_LABPRO 0x0001
+#define USB_PRODUCT_LABQUEST 0x0005
+
+#define VST_MAXBUFFER (64*1024)
+
+static struct usb_device_id id_table[] = {
+ { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)},
+ { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)},
+ { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB650)},
+ { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB4000)},
+ { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB325)},
+ { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABQUEST)},
+ { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABPRO)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct vstusb_device {
+ struct kref kref;
+ struct mutex lock;
+ struct usb_device *usb_dev;
+ char present;
+ char isopen;
+ struct usb_anchor submitted;
+ int rd_pipe;
+ int rd_timeout_ms;
+ int wr_pipe;
+ int wr_timeout_ms;
+};
+#define to_vst_dev(d) container_of(d, struct vstusb_device, kref)
+
+static struct usb_driver vstusb_driver;
+
+static void vstusb_delete(struct kref *kref)
+{
+ struct vstusb_device *vstdev = to_vst_dev(kref);
+
+ usb_put_dev(vstdev->usb_dev);
+ kfree(vstdev);
+}
+
+static int vstusb_open(struct inode *inode, struct file *file)
+{
+ struct vstusb_device *vstdev;
+ struct usb_interface *interface;
+
+ interface = usb_find_interface(&vstusb_driver, iminor(inode));
+
+ if (!interface) {
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s - error, can't find device for minor %d\n",
+ __func__, iminor(inode));
+ return -ENODEV;
+ }
+
+ vstdev = usb_get_intfdata(interface);
+
+ if (!vstdev)
+ return -ENODEV;
+
+ /* lock this device */
+ mutex_lock(&vstdev->lock);
+
+ /* can only open one time */
+ if ((!vstdev->present) || (vstdev->isopen)) {
+ mutex_unlock(&vstdev->lock);
+ return -EBUSY;
+ }
+
+ /* increment our usage count */
+ kref_get(&vstdev->kref);
+
+ vstdev->isopen = 1;
+
+ /* save device in the file's private structure */
+ file->private_data = vstdev;
+
+ dev_dbg(&vstdev->usb_dev->dev, "%s: opened\n", __func__);
+
+ mutex_unlock(&vstdev->lock);
+
+ return 0;
+}
+
+static int vstusb_release(struct inode *inode, struct file *file)
+{
+ struct vstusb_device *vstdev;
+
+ vstdev = file->private_data;
+
+ if (vstdev == NULL)
+ return -ENODEV;
+
+ mutex_lock(&vstdev->lock);
+
+ vstdev->isopen = 0;
+
+ dev_dbg(&vstdev->usb_dev->dev, "%s: released\n", __func__);
+
+ mutex_unlock(&vstdev->lock);
+
+ kref_put(&vstdev->kref, vstusb_delete);
+
+ return 0;
+}
+
+static void usb_api_blocking_completion(struct urb *urb)
+{
+ struct completion *completeit = urb->context;
+
+ complete(completeit);
+}
+
+static int vstusb_fill_and_send_urb(struct urb *urb,
+ struct usb_device *usb_dev,
+ unsigned int pipe, void *data,
+ unsigned int len, struct completion *done)
+{
+ struct usb_host_endpoint *ep;
+ struct usb_host_endpoint **hostep;
+ unsigned int pipend;
+
+ int status;
+
+ hostep = usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out;
+ pipend = usb_pipeendpoint(pipe);
+ ep = hostep[pipend];
+
+ if (!ep || (len == 0))
+ return -EINVAL;
+
+ if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT) {
+ pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
+ usb_fill_int_urb(urb, usb_dev, pipe, data, len,
+ (usb_complete_t)usb_api_blocking_completion,
+ NULL, ep->desc.bInterval);
+ } else
+ usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
+ (usb_complete_t)usb_api_blocking_completion,
+ NULL);
+
+ init_completion(done);
+ urb->context = done;
+ urb->actual_length = 0;
+ status = usb_submit_urb(urb, GFP_KERNEL);
+
+ return status;
+}
+
+static int vstusb_complete_urb(struct urb *urb, struct completion *done,
+ int timeout, int *actual_length)
+{
+ unsigned long expire;
+ int status;
+
+ expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
+ if (!wait_for_completion_interruptible_timeout(done, expire)) {
+ usb_kill_urb(urb);
+ status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
+
+ dev_dbg(&urb->dev->dev,
+ "%s timed out on ep%d%s len=%d/%d, urb status = %d\n",
+ current->comm,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb->actual_length,
+ urb->transfer_buffer_length,
+ urb->status);
+
+ } else {
+ if (signal_pending(current)) {
+ /* if really an error */
+ if (urb->status && !((urb->status == -ENOENT) ||
+ (urb->status == -ECONNRESET) ||
+ (urb->status == -ESHUTDOWN))) {
+ status = -EINTR;
+ usb_kill_urb(urb);
+ } else {
+ status = 0;
+ }
+
+ dev_dbg(&urb->dev->dev,
+ "%s: signal pending on ep%d%s len=%d/%d,"
+ "urb status = %d\n",
+ current->comm,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb->actual_length,
+ urb->transfer_buffer_length,
+ urb->status);
+
+ } else {
+ status = urb->status;
+ }
+ }
+
+ if (actual_length)
+ *actual_length = urb->actual_length;
+
+ return status;
+}
+
+static ssize_t vstusb_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct vstusb_device *vstdev;
+ int cnt = -1;
+ void *buf;
+ int retval = 0;
+
+ struct urb *urb;
+ struct usb_device *dev;
+ unsigned int pipe;
+ int timeout;
+
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ vstdev = file->private_data;
+
+ if (vstdev == NULL)
+ return -ENODEV;
+
+ /* verify that we actually want to read some data */
+ if ((count == 0) || (count > VST_MAXBUFFER))
+ return -EINVAL;
+
+ /* lock this object */
+ if (mutex_lock_interruptible(&vstdev->lock))
+ return -ERESTARTSYS;
+
+ /* anyone home */
+ if (!vstdev->present) {
+ mutex_unlock(&vstdev->lock);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: device not present\n", __func__);
+ return -ENODEV;
+ }
+
+ /* pull out the necessary data */
+ dev = vstdev->usb_dev;
+ pipe = usb_rcvbulkpipe(dev, vstdev->rd_pipe);
+ timeout = vstdev->rd_timeout_ms;
+
+ buf = kmalloc(count, GFP_KERNEL);
+ if (buf == NULL) {
+ mutex_unlock(&vstdev->lock);
+ return -ENOMEM;
+ }
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ kfree(buf);
+ mutex_unlock(&vstdev->lock);
+ return -ENOMEM;
+ }
+
+ usb_anchor_urb(urb, &vstdev->submitted);
+ retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done);
+ mutex_unlock(&vstdev->lock);
+ if (retval) {
+ usb_unanchor_urb(urb);
+ dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n",
+ __func__, retval, pipe);
+ goto exit;
+ }
+
+ retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
+ if (retval) {
+ dev_err(&dev->dev, "%s: error %d completing urb %d\n",
+ __func__, retval, pipe);
+ goto exit;
+ }
+
+ if (copy_to_user(buffer, buf, cnt)) {
+ dev_err(&dev->dev, "%s: can't copy_to_user\n", __func__);
+ retval = -EFAULT;
+ } else {
+ retval = cnt;
+ dev_dbg(&dev->dev, "%s: read %d bytes from pipe %d\n",
+ __func__, cnt, pipe);
+ }
+
+exit:
+ usb_free_urb(urb);
+ kfree(buf);
+ return retval;
+}
+
+static ssize_t vstusb_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct vstusb_device *vstdev;
+ int cnt = -1;
+ void *buf;
+ int retval = 0;
+
+ struct urb *urb;
+ struct usb_device *dev;
+ unsigned int pipe;
+ int timeout;
+
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ vstdev = file->private_data;
+
+ if (vstdev == NULL)
+ return -ENODEV;
+
+ /* verify that we actually have some data to write */
+ if ((count == 0) || (count > VST_MAXBUFFER))
+ return retval;
+
+ /* lock this object */
+ if (mutex_lock_interruptible(&vstdev->lock))
+ return -ERESTARTSYS;
+
+ /* anyone home */
+ if (!vstdev->present) {
+ mutex_unlock(&vstdev->lock);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: device not present\n", __func__);
+ return -ENODEV;
+ }
+
+ /* pull out the necessary data */
+ dev = vstdev->usb_dev;
+ pipe = usb_sndbulkpipe(dev, vstdev->wr_pipe);
+ timeout = vstdev->wr_timeout_ms;
+
+ buf = kmalloc(count, GFP_KERNEL);
+ if (buf == NULL) {
+ mutex_unlock(&vstdev->lock);
+ return -ENOMEM;
+ }
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ kfree(buf);
+ mutex_unlock(&vstdev->lock);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(buf, buffer, count)) {
+ dev_err(&dev->dev, "%s: can't copy_from_user\n", __func__);
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ usb_anchor_urb(urb, &vstdev->submitted);
+ retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done);
+ mutex_unlock(&vstdev->lock);
+ if (retval) {
+ usb_unanchor_urb(urb);
+ dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n",
+ __func__, retval, pipe);
+ goto exit;
+ }
+
+ retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
+ if (retval) {
+ dev_err(&dev->dev, "%s: error %d completing urb %d\n",
+ __func__, retval, pipe);
+ goto exit;
+ } else {
+ retval = cnt;
+ dev_dbg(&dev->dev, "%s: sent %d bytes to pipe %d\n",
+ __func__, cnt, pipe);
+ }
+
+exit:
+ usb_free_urb(urb);
+ kfree(buf);
+ return retval;
+}
+
+static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ int cnt = -1;
+ void __user *data = (void __user *)arg;
+ struct vstusb_args usb_data;
+
+ struct vstusb_device *vstdev;
+ void *buffer = NULL; /* must be initialized. buffer is
+ * referenced on exit but not all
+ * ioctls allocate it */
+
+ struct urb *urb = NULL; /* must be initialized. urb is
+ * referenced on exit but not all
+ * ioctls allocate it */
+ struct usb_device *dev;
+ unsigned int pipe;
+ int timeout;
+
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ vstdev = file->private_data;
+
+ if (_IOC_TYPE(cmd) != VST_IOC_MAGIC) {
+ dev_warn(&vstdev->usb_dev->dev,
+ "%s: ioctl command %x, bad ioctl magic %x, "
+ "expected %x\n", __func__, cmd,
+ _IOC_TYPE(cmd), VST_IOC_MAGIC);
+ return -EINVAL;
+ }
+
+ if (vstdev == NULL)
+ return -ENODEV;
+
+ if (copy_from_user(&usb_data, data, sizeof(struct vstusb_args))) {
+ dev_err(&vstdev->usb_dev->dev, "%s: can't copy_from_user\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ /* lock this object */
+ if (mutex_lock_interruptible(&vstdev->lock)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ /* anyone home */
+ if (!vstdev->present) {
+ mutex_unlock(&vstdev->lock);
+ dev_err(&vstdev->usb_dev->dev, "%s: device not present\n",
+ __func__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* pull out the necessary data */
+ dev = vstdev->usb_dev;
+
+ switch (cmd) {
+
+ case IOCTL_VSTUSB_CONFIG_RW:
+
+ vstdev->rd_pipe = usb_data.rd_pipe;
+ vstdev->rd_timeout_ms = usb_data.rd_timeout_ms;
+ vstdev->wr_pipe = usb_data.wr_pipe;
+ vstdev->wr_timeout_ms = usb_data.wr_timeout_ms;
+
+ mutex_unlock(&vstdev->lock);
+
+ dev_dbg(&dev->dev, "%s: setting pipes/timeouts, "
+ "rdpipe = %d, rdtimeout = %d, "
+ "wrpipe = %d, wrtimeout = %d\n", __func__,
+ vstdev->rd_pipe, vstdev->rd_timeout_ms,
+ vstdev->wr_pipe, vstdev->wr_timeout_ms);
+ break;
+
+ case IOCTL_VSTUSB_SEND_PIPE:
+
+ if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
+ mutex_unlock(&vstdev->lock);
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ buffer = kmalloc(usb_data.count, GFP_KERNEL);
+ if (buffer == NULL) {
+ mutex_unlock(&vstdev->lock);
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ mutex_unlock(&vstdev->lock);
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ timeout = usb_data.timeout_ms;
+
+ pipe = usb_sndbulkpipe(dev, usb_data.pipe);
+
+ if (copy_from_user(buffer, usb_data.buffer, usb_data.count)) {
+ dev_err(&dev->dev, "%s: can't copy_from_user\n",
+ __func__);
+ mutex_unlock(&vstdev->lock);
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ usb_anchor_urb(urb, &vstdev->submitted);
+ retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer,
+ usb_data.count, &done);
+ mutex_unlock(&vstdev->lock);
+ if (retval) {
+ usb_unanchor_urb(urb);
+ dev_err(&dev->dev,
+ "%s: error %d filling and sending urb %d\n",
+ __func__, retval, pipe);
+ goto exit;
+ }
+
+ retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
+ if (retval) {
+ dev_err(&dev->dev, "%s: error %d completing urb %d\n",
+ __func__, retval, pipe);
+ }
+
+ break;
+ case IOCTL_VSTUSB_RECV_PIPE:
+
+ if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
+ mutex_unlock(&vstdev->lock);
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ buffer = kmalloc(usb_data.count, GFP_KERNEL);
+ if (buffer == NULL) {
+ mutex_unlock(&vstdev->lock);
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ mutex_unlock(&vstdev->lock);
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ timeout = usb_data.timeout_ms;
+
+ pipe = usb_rcvbulkpipe(dev, usb_data.pipe);
+
+ usb_anchor_urb(urb, &vstdev->submitted);
+ retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer,
+ usb_data.count, &done);
+ mutex_unlock(&vstdev->lock);
+ if (retval) {
+ usb_unanchor_urb(urb);
+ dev_err(&dev->dev,
+ "%s: error %d filling and sending urb %d\n",
+ __func__, retval, pipe);
+ goto exit;
+ }
+
+ retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
+ if (retval) {
+ dev_err(&dev->dev, "%s: error %d completing urb %d\n",
+ __func__, retval, pipe);
+ goto exit;
+ }
+
+ if (copy_to_user(usb_data.buffer, buffer, cnt)) {
+ dev_err(&dev->dev, "%s: can't copy_to_user\n",
+ __func__);
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ usb_data.count = cnt;
+ if (copy_to_user(data, &usb_data, sizeof(struct vstusb_args))) {
+ dev_err(&dev->dev, "%s: can't copy_to_user\n",
+ __func__);
+ retval = -EFAULT;
+ } else {
+ dev_dbg(&dev->dev, "%s: recv %d bytes from pipe %d\n",
+ __func__, usb_data.count, usb_data.pipe);
+ }
+
+ break;
+
+ default:
+ mutex_unlock(&vstdev->lock);
+ dev_warn(&dev->dev, "ioctl_vstusb: invalid ioctl cmd %x\n",
+ cmd);
+ return -EINVAL;
+ break;
+ }
+exit:
+ usb_free_urb(urb);
+ kfree(buffer);
+ return retval;
+}
+
+static const struct file_operations vstusb_fops = {
+ .owner = THIS_MODULE,
+ .read = vstusb_read,
+ .write = vstusb_write,
+ .unlocked_ioctl = vstusb_ioctl,
+ .compat_ioctl = vstusb_ioctl,
+ .open = vstusb_open,
+ .release = vstusb_release,
+};
+
+static struct usb_class_driver usb_vstusb_class = {
+ .name = "usb/vstusb%d",
+ .fops = &vstusb_fops,
+ .minor_base = VSTUSB_MINOR_BASE,
+};
+
+static int vstusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct vstusb_device *vstdev;
+ int i;
+ int retval = 0;
+
+ /* allocate memory for our device state and intialize it */
+
+ vstdev = kzalloc(sizeof(*vstdev), GFP_KERNEL);
+ if (vstdev == NULL)
+ return -ENOMEM;
+
+ /* must do usb_get_dev() prior to kref_init() since the kref_put()
+ * release function will do a usb_put_dev() */
+ usb_get_dev(dev);
+ kref_init(&vstdev->kref);
+ mutex_init(&vstdev->lock);
+
+ i = dev->descriptor.bcdDevice;
+
+ dev_dbg(&intf->dev, "Version %1d%1d.%1d%1d found at address %d\n",
+ (i & 0xF000) >> 12, (i & 0xF00) >> 8,
+ (i & 0xF0) >> 4, (i & 0xF), dev->devnum);
+
+ vstdev->present = 1;
+ vstdev->isopen = 0;
+ vstdev->usb_dev = dev;
+ init_usb_anchor(&vstdev->submitted);
+
+ usb_set_intfdata(intf, vstdev);
+ retval = usb_register_dev(intf, &usb_vstusb_class);
+ if (retval) {
+ dev_err(&intf->dev,
+ "%s: Not able to get a minor for this device.\n",
+ __func__);
+ usb_set_intfdata(intf, NULL);
+ kref_put(&vstdev->kref, vstusb_delete);
+ return retval;
+ }
+
+ /* let the user know what node this device is now attached to */
+ dev_info(&intf->dev,
+ "VST USB Device #%d now attached to major %d minor %d\n",
+ (intf->minor - VSTUSB_MINOR_BASE), USB_MAJOR, intf->minor);
+
+ dev_info(&intf->dev, "%s, %s\n", DRIVER_DESC, DRIVER_VERSION);
+
+ return retval;
+}
+
+static void vstusb_disconnect(struct usb_interface *intf)
+{
+ struct vstusb_device *vstdev = usb_get_intfdata(intf);
+
+ usb_deregister_dev(intf, &usb_vstusb_class);
+ usb_set_intfdata(intf, NULL);
+
+ if (vstdev) {
+
+ mutex_lock(&vstdev->lock);
+ vstdev->present = 0;
+
+ usb_kill_anchored_urbs(&vstdev->submitted);
+
+ mutex_unlock(&vstdev->lock);
+
+ kref_put(&vstdev->kref, vstusb_delete);
+ }
+
+}
+
+static int vstusb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct vstusb_device *vstdev = usb_get_intfdata(intf);
+ int time;
+ if (!vstdev)
+ return 0;
+
+ mutex_lock(&vstdev->lock);
+ time = usb_wait_anchor_empty_timeout(&vstdev->submitted, 1000);
+ if (!time)
+ usb_kill_anchored_urbs(&vstdev->submitted);
+ mutex_unlock(&vstdev->lock);
+
+ return 0;
+}
+
+static int vstusb_resume(struct usb_interface *intf)
+{
+ return 0;
+}
+
+static struct usb_driver vstusb_driver = {
+ .name = "vstusb",
+ .probe = vstusb_probe,
+ .disconnect = vstusb_disconnect,
+ .suspend = vstusb_suspend,
+ .resume = vstusb_resume,
+ .id_table = id_table,
+};
+
+static int __init vstusb_init(void)
+{
+ int rc;
+
+ rc = usb_register(&vstusb_driver);
+ if (rc)
+ printk(KERN_ERR "%s: failed to register (%d)", __func__, rc);
+
+ return rc;
+}
+
+static void __exit vstusb_exit(void)
+{
+ usb_deregister(&vstusb_driver);
+}
+
+module_init(vstusb_init);
+module_exit(vstusb_exit);
+
+MODULE_AUTHOR("Dennis O'Brien/Stephen Ware");
+MODULE_DESCRIPTION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 442d8076b20..5e0ab4201c0 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -361,12 +361,12 @@ static int __init mon_init(void)
}
// MOD_INC_USE_COUNT(which_module?);
- usb_register_notify(&mon_nb);
mutex_lock(&usb_bus_list_lock);
list_for_each_entry (ubus, &usb_bus_list, bus_list) {
mon_bus_init(ubus);
}
+ usb_register_notify(&mon_nb);
mutex_unlock(&usb_bus_list_lock);
return 0;
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 58b2b8fc943..4b9542bbb35 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -33,10 +33,6 @@ config USB_MUSB_SOC
default y if ARCH_DAVINCI
default y if ARCH_OMAP2430
default y if ARCH_OMAP34XX
- help
- Use a static <asm/arch/hdrc_cnf.h> file to describe how the
- controller is configured (endpoints, mechanisms, etc) on the
- current iteration of a given system-on-chip.
comment "DaVinci 644x USB support"
depends on USB_MUSB_HDRC && ARCH_DAVINCI
diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h
index fc5216b5d2c..729b4071787 100644
--- a/drivers/usb/musb/cppi_dma.h
+++ b/drivers/usb/musb/cppi_dma.h
@@ -119,8 +119,8 @@ struct cppi {
void __iomem *mregs; /* Mentor regs */
void __iomem *tibase; /* TI/CPPI regs */
- struct cppi_channel tx[MUSB_C_NUM_EPT - 1];
- struct cppi_channel rx[MUSB_C_NUM_EPR - 1];
+ struct cppi_channel tx[4];
+ struct cppi_channel rx[4];
struct dma_pool *pool;
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 75baf181a8c..dfb3bcbe00f 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -30,6 +30,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/gpio.h>
#include <asm/arch/hardware.h>
#include <asm/arch/memory.h>
@@ -39,7 +40,7 @@
#include "musb_core.h"
#ifdef CONFIG_MACH_DAVINCI_EVM
-#include <asm/arch/i2c-client.h>
+#define GPIO_nVBUS_DRV 87
#endif
#include "davinci.h"
@@ -138,7 +139,6 @@ static int vbus_state = -1;
/* VBUS SWITCHING IS BOARD-SPECIFIC */
#ifdef CONFIG_MACH_DAVINCI_EVM
-#ifndef CONFIG_MACH_DAVINCI_EVM_OTG
/* I2C operations are always synchronous, and require a task context.
* With unloaded systems, using the shared workqueue seems to suffice
@@ -146,12 +146,11 @@ static int vbus_state = -1;
*/
static void evm_deferred_drvvbus(struct work_struct *ignored)
{
- davinci_i2c_expander_op(0x3a, USB_DRVVBUS, vbus_state);
+ gpio_set_value_cansleep(GPIO_nVBUS_DRV, vbus_state);
vbus_state = !vbus_state;
}
static DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus);
-#endif /* modified board */
#endif /* EVM */
static void davinci_source_power(struct musb *musb, int is_on, int immediate)
@@ -165,21 +164,10 @@ static void davinci_source_power(struct musb *musb, int is_on, int immediate)
#ifdef CONFIG_MACH_DAVINCI_EVM
if (machine_is_davinci_evm()) {
-#ifdef CONFIG_MACH_DAVINCI_EVM_OTG
- /* modified EVM board switching VBUS with GPIO(6) not I2C
- * NOTE: PINMUX0.RGB888 (bit23) must be clear
- */
- if (is_on)
- gpio_set(GPIO(6));
- else
- gpio_clear(GPIO(6));
- immediate = 1;
-#else
if (immediate)
- davinci_i2c_expander_op(0x3a, USB_DRVVBUS, !is_on);
+ gpio_set_value_cansleep(GPIO_nVBUS_DRV, vbus_state);
else
schedule_work(&evm_vbus_work);
-#endif
}
#endif
if (immediate)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 128e949db47..4a35745b30b 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -82,9 +82,9 @@
/*
* This gets many kinds of configuration information:
* - Kconfig for everything user-configurable
- * - <asm/arch/hdrc_cnf.h> for SOC or family details
* - platform_device for addressing, irq, and platform_data
* - platform_data is mostly for board-specific informarion
+ * (plus recentrly, SOC or family details)
*
* Most of the conditional compilation will (someday) vanish.
*/
@@ -974,9 +974,9 @@ static void musb_shutdown(struct platform_device *pdev)
/*
* The silicon either has hard-wired endpoint configurations, or else
* "dynamic fifo" sizing. The driver has support for both, though at this
- * writing only the dynamic sizing is very well tested. We use normal
- * idioms to so both modes are compile-tested, but dead code elimination
- * leaves only the relevant one in the object file.
+ * writing only the dynamic sizing is very well tested. Since we switched
+ * away from compile-time hardware parameters, we can no longer rely on
+ * dead code elimination to leave only the relevant one in the object file.
*
* We don't currently use dynamic fifo setup capability to do anything
* more than selecting one of a bunch of predefined configurations.
@@ -1806,6 +1806,7 @@ allocate_instance(struct device *dev,
musb->ctrl_base = mbase;
musb->nIrq = -ENODEV;
musb->config = config;
+ BUG_ON(musb->config->num_eps > MUSB_C_NUM_EPS);
for (epnum = 0, ep = musb->endpoints;
epnum < musb->config->num_eps;
epnum++, ep++) {
@@ -2054,15 +2055,6 @@ bad_config:
}
- return 0;
-
-fail:
- if (musb->clock)
- clk_put(musb->clock);
- device_init_wakeup(dev, 0);
- musb_free(musb);
- return status;
-
#ifdef CONFIG_SYSFS
status = device_create_file(dev, &dev_attr_mode);
status = device_create_file(dev, &dev_attr_vbus);
@@ -2071,12 +2063,31 @@ fail:
#endif /* CONFIG_USB_GADGET_MUSB_HDRC */
status = 0;
#endif
+ if (status)
+ goto fail2;
- return status;
+ return 0;
fail2:
+#ifdef CONFIG_SYSFS
+ device_remove_file(musb->controller, &dev_attr_mode);
+ device_remove_file(musb->controller, &dev_attr_vbus);
+#ifdef CONFIG_USB_MUSB_OTG
+ device_remove_file(musb->controller, &dev_attr_srp);
+#endif
+#endif
musb_platform_exit(musb);
- goto fail;
+fail:
+ dev_err(musb->controller,
+ "musb_init_controller failed with status %d\n", status);
+
+ if (musb->clock)
+ clk_put(musb->clock);
+ device_init_wakeup(dev, 0);
+ musb_free(musb);
+
+ return status;
+
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index a57652fff39..3f5e30ddfa2 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -437,7 +437,7 @@ static void ep0_rxstate(struct musb *musb)
{
void __iomem *regs = musb->control_ep->regs;
struct usb_request *req;
- u16 tmp;
+ u16 count, csr;
req = next_ep0_request(musb);
@@ -449,35 +449,35 @@ static void ep0_rxstate(struct musb *musb)
unsigned len = req->length - req->actual;
/* read the buffer */
- tmp = musb_readb(regs, MUSB_COUNT0);
- if (tmp > len) {
+ count = musb_readb(regs, MUSB_COUNT0);
+ if (count > len) {
req->status = -EOVERFLOW;
- tmp = len;
+ count = len;
}
- musb_read_fifo(&musb->endpoints[0], tmp, buf);
- req->actual += tmp;
- tmp = MUSB_CSR0_P_SVDRXPKTRDY;
- if (tmp < 64 || req->actual == req->length) {
+ musb_read_fifo(&musb->endpoints[0], count, buf);
+ req->actual += count;
+ csr = MUSB_CSR0_P_SVDRXPKTRDY;
+ if (count < 64 || req->actual == req->length) {
musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
- tmp |= MUSB_CSR0_P_DATAEND;
+ csr |= MUSB_CSR0_P_DATAEND;
} else
req = NULL;
} else
- tmp = MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_SENDSTALL;
+ csr = MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_SENDSTALL;
/* Completion handler may choose to stall, e.g. because the
* message just received holds invalid data.
*/
if (req) {
- musb->ackpend = tmp;
+ musb->ackpend = csr;
musb_g_ep0_giveback(musb, req);
if (!musb->ackpend)
return;
musb->ackpend = 0;
}
musb_ep_select(musb->mregs, 0);
- musb_writew(regs, MUSB_CSR0, tmp);
+ musb_writew(regs, MUSB_CSR0, csr);
}
/*
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 8b4be012669..3133990f04e 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -108,7 +108,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
/*
* Clear TX fifo. Needed to avoid BABBLE errors.
*/
-static inline void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
+static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
{
void __iomem *epio = ep->regs;
u16 csr;
@@ -291,6 +291,7 @@ __acquires(musb->lock)
urb->actual_length, urb->transfer_buffer_length
);
+ usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb);
spin_unlock(&musb->lock);
usb_hcd_giveback_urb(musb_to_hcd(musb), urb, status);
spin_lock(&musb->lock);
@@ -353,8 +354,6 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
break;
}
- usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb);
-
qh->is_ready = 0;
__musb_giveback(musb, urb, status);
qh->is_ready = ready;
@@ -436,7 +435,7 @@ musb_advance_schedule(struct musb *musb, struct urb *urb,
}
}
-static inline u16 musb_h_flush_rxfifo(struct musb_hw_ep *hw_ep, u16 csr)
+static u16 musb_h_flush_rxfifo(struct musb_hw_ep *hw_ep, u16 csr)
{
/* we don't want fifo to fill itself again;
* ignore dma (various models),
@@ -1005,7 +1004,7 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
/*
* Handle default endpoint interrupt as host. Only called in IRQ time
- * from the LinuxIsr() interrupt service routine.
+ * from musb_interrupt().
*
* called with controller irqlocked
*/
@@ -1791,7 +1790,9 @@ static int musb_urb_enqueue(
*/
qh = kzalloc(sizeof *qh, mem_flags);
if (!qh) {
+ spin_lock_irqsave(&musb->lock, flags);
usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&musb->lock, flags);
return -ENOMEM;
}
@@ -1873,7 +1874,11 @@ static int musb_urb_enqueue(
/* set up tt info if needed */
if (urb->dev->tt) {
qh->h_port_reg = (u8) urb->dev->ttport;
- qh->h_addr_reg |= 0x80;
+ if (urb->dev->tt->hub)
+ qh->h_addr_reg =
+ (u8) urb->dev->tt->hub->devnum;
+ if (urb->dev->tt->multi)
+ qh->h_addr_reg |= 0x80;
}
}
}
@@ -1903,7 +1908,9 @@ static int musb_urb_enqueue(
done:
if (ret != 0) {
+ spin_lock_irqsave(&musb->lock, flags);
usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&musb->lock, flags);
kfree(qh);
}
return ret;
diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h
index 6bbedae83af..223f0a51409 100644
--- a/drivers/usb/musb/musb_io.h
+++ b/drivers/usb/musb/musb_io.h
@@ -37,7 +37,9 @@
#include <linux/io.h>
-#ifndef CONFIG_ARM
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
+ && !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \
+ && !defined(CONFIG_PPC64)
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)
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 9ba8fb7fcd2..8c734ef2c1e 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -45,8 +45,8 @@
#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_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \
+ (MUSB_HSDMA_BASE + (_bchannel << 4) + _offset)
/* control register (16-bit): */
#define MUSB_HSDMA_ENABLE_SHIFT 0
@@ -67,23 +67,23 @@
struct musb_dma_controller;
struct musb_dma_channel {
- struct dma_channel Channel;
+ struct dma_channel channel;
struct musb_dma_controller *controller;
- u32 dwStartAddress;
+ u32 start_addr;
u32 len;
- u16 wMaxPacketSize;
- u8 bIndex;
+ u16 max_packet_sz;
+ u8 idx;
u8 epnum;
u8 transmit;
};
struct musb_dma_controller {
- struct dma_controller Controller;
- struct musb_dma_channel aChannel[MUSB_HSDMA_CHANNELS];
- void *pDmaPrivate;
- void __iomem *pCoreBase;
- u8 bChannelCount;
- u8 bmUsedChannels;
+ 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;
};
@@ -93,91 +93,91 @@ static int dma_controller_start(struct dma_controller *c)
return 0;
}
-static void dma_channel_release(struct dma_channel *pChannel);
+static void dma_channel_release(struct dma_channel *channel);
static int dma_controller_stop(struct dma_controller *c)
{
- struct musb_dma_controller *controller =
- container_of(c, struct musb_dma_controller, Controller);
- struct musb *musb = (struct musb *) controller->pDmaPrivate;
- struct dma_channel *pChannel;
- u8 bBit;
+ struct musb_dma_controller *controller = container_of(c,
+ struct musb_dma_controller, controller);
+ struct musb *musb = controller->private_data;
+ struct dma_channel *channel;
+ u8 bit;
- if (controller->bmUsedChannels != 0) {
+ if (controller->used_channels != 0) {
dev_err(musb->controller,
"Stopping DMA controller while channel active\n");
- for (bBit = 0; bBit < MUSB_HSDMA_CHANNELS; bBit++) {
- if (controller->bmUsedChannels & (1 << bBit)) {
- pChannel = &controller->aChannel[bBit].Channel;
- dma_channel_release(pChannel);
+ for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) {
+ if (controller->used_channels & (1 << bit)) {
+ channel = &controller->channel[bit].channel;
+ dma_channel_release(channel);
- if (!controller->bmUsedChannels)
+ if (!controller->used_channels)
break;
}
}
}
+
return 0;
}
static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
struct musb_hw_ep *hw_ep, u8 transmit)
{
- u8 bBit;
- struct dma_channel *pChannel = NULL;
- struct musb_dma_channel *pImplChannel = NULL;
- struct musb_dma_controller *controller =
- container_of(c, struct musb_dma_controller, Controller);
-
- for (bBit = 0; bBit < MUSB_HSDMA_CHANNELS; bBit++) {
- if (!(controller->bmUsedChannels & (1 << bBit))) {
- controller->bmUsedChannels |= (1 << bBit);
- pImplChannel = &(controller->aChannel[bBit]);
- pImplChannel->controller = controller;
- pImplChannel->bIndex = bBit;
- pImplChannel->epnum = hw_ep->epnum;
- pImplChannel->transmit = transmit;
- pChannel = &(pImplChannel->Channel);
- pChannel->private_data = pImplChannel;
- pChannel->status = MUSB_DMA_STATUS_FREE;
- pChannel->max_len = 0x10000;
+ struct musb_dma_controller *controller = container_of(c,
+ struct musb_dma_controller, controller);
+ struct musb_dma_channel *musb_channel = NULL;
+ struct dma_channel *channel = NULL;
+ u8 bit;
+
+ for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) {
+ if (!(controller->used_channels & (1 << bit))) {
+ controller->used_channels |= (1 << bit);
+ musb_channel = &(controller->channel[bit]);
+ musb_channel->controller = controller;
+ musb_channel->idx = bit;
+ musb_channel->epnum = hw_ep->epnum;
+ musb_channel->transmit = transmit;
+ channel = &(musb_channel->channel);
+ channel->private_data = musb_channel;
+ channel->status = MUSB_DMA_STATUS_FREE;
+ channel->max_len = 0x10000;
/* Tx => mode 1; Rx => mode 0 */
- pChannel->desired_mode = transmit;
- pChannel->actual_len = 0;
+ channel->desired_mode = transmit;
+ channel->actual_len = 0;
break;
}
}
- return pChannel;
+
+ return channel;
}
-static void dma_channel_release(struct dma_channel *pChannel)
+static void dma_channel_release(struct dma_channel *channel)
{
- struct musb_dma_channel *pImplChannel =
- (struct musb_dma_channel *) pChannel->private_data;
+ struct musb_dma_channel *musb_channel = channel->private_data;
- pChannel->actual_len = 0;
- pImplChannel->dwStartAddress = 0;
- pImplChannel->len = 0;
+ channel->actual_len = 0;
+ musb_channel->start_addr = 0;
+ musb_channel->len = 0;
- pImplChannel->controller->bmUsedChannels &=
- ~(1 << pImplChannel->bIndex);
+ musb_channel->controller->used_channels &=
+ ~(1 << musb_channel->idx);
- pChannel->status = MUSB_DMA_STATUS_UNKNOWN;
+ channel->status = MUSB_DMA_STATUS_UNKNOWN;
}
-static void configure_channel(struct dma_channel *pChannel,
+static void configure_channel(struct dma_channel *channel,
u16 packet_sz, u8 mode,
dma_addr_t dma_addr, u32 len)
{
- struct musb_dma_channel *pImplChannel =
- (struct musb_dma_channel *) pChannel->private_data;
- struct musb_dma_controller *controller = pImplChannel->controller;
- void __iomem *mbase = controller->pCoreBase;
- u8 bChannel = pImplChannel->bIndex;
+ struct musb_dma_channel *musb_channel = channel->private_data;
+ struct musb_dma_controller *controller = musb_channel->controller;
+ void __iomem *mbase = controller->base;
+ u8 bchannel = musb_channel->idx;
u16 csr = 0;
DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
- pChannel, packet_sz, dma_addr, len, mode);
+ channel, packet_sz, dma_addr, len, mode);
if (mode) {
csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
@@ -195,180 +195,183 @@ static void configure_channel(struct dma_channel *pChannel,
}
}
- csr |= (pImplChannel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT)
+ csr |= (musb_channel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT)
| (1 << MUSB_HSDMA_ENABLE_SHIFT)
| (1 << MUSB_HSDMA_IRQENABLE_SHIFT)
- | (pImplChannel->transmit
+ | (musb_channel->transmit
? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
: 0);
/* address/count */
musb_writel(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS),
dma_addr);
musb_writel(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT),
len);
/* control (this should start things) */
musb_writew(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL),
csr);
}
-static int dma_channel_program(struct dma_channel *pChannel,
+static int dma_channel_program(struct dma_channel *channel,
u16 packet_sz, u8 mode,
dma_addr_t dma_addr, u32 len)
{
- struct musb_dma_channel *pImplChannel =
- (struct musb_dma_channel *) pChannel->private_data;
+ struct musb_dma_channel *musb_channel = channel->private_data;
DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
- pImplChannel->epnum,
- pImplChannel->transmit ? "Tx" : "Rx",
+ musb_channel->epnum,
+ musb_channel->transmit ? "Tx" : "Rx",
packet_sz, dma_addr, len, mode);
- BUG_ON(pChannel->status == MUSB_DMA_STATUS_UNKNOWN ||
- pChannel->status == MUSB_DMA_STATUS_BUSY);
+ BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
+ channel->status == MUSB_DMA_STATUS_BUSY);
- pChannel->actual_len = 0;
- pImplChannel->dwStartAddress = dma_addr;
- pImplChannel->len = len;
- pImplChannel->wMaxPacketSize = packet_sz;
- pChannel->status = MUSB_DMA_STATUS_BUSY;
+ channel->actual_len = 0;
+ musb_channel->start_addr = dma_addr;
+ musb_channel->len = len;
+ musb_channel->max_packet_sz = packet_sz;
+ channel->status = MUSB_DMA_STATUS_BUSY;
if ((mode == 1) && (len >= packet_sz))
- configure_channel(pChannel, packet_sz, 1, dma_addr, len);
+ configure_channel(channel, packet_sz, 1, dma_addr, len);
else
- configure_channel(pChannel, packet_sz, 0, dma_addr, len);
+ configure_channel(channel, packet_sz, 0, dma_addr, len);
return true;
}
-static int dma_channel_abort(struct dma_channel *pChannel)
+static int dma_channel_abort(struct dma_channel *channel)
{
- struct musb_dma_channel *pImplChannel =
- (struct musb_dma_channel *) pChannel->private_data;
- u8 bChannel = pImplChannel->bIndex;
- void __iomem *mbase = pImplChannel->controller->pCoreBase;
+ struct musb_dma_channel *musb_channel = channel->private_data;
+ void __iomem *mbase = musb_channel->controller->base;
+
+ u8 bchannel = musb_channel->idx;
u16 csr;
- if (pChannel->status == MUSB_DMA_STATUS_BUSY) {
- if (pImplChannel->transmit) {
+ if (channel->status == MUSB_DMA_STATUS_BUSY) {
+ if (musb_channel->transmit) {
csr = musb_readw(mbase,
- MUSB_EP_OFFSET(pImplChannel->epnum,
+ MUSB_EP_OFFSET(musb_channel->epnum,
MUSB_TXCSR));
csr &= ~(MUSB_TXCSR_AUTOSET |
MUSB_TXCSR_DMAENAB |
MUSB_TXCSR_DMAMODE);
musb_writew(mbase,
- MUSB_EP_OFFSET(pImplChannel->epnum,
- MUSB_TXCSR),
+ MUSB_EP_OFFSET(musb_channel->epnum, MUSB_TXCSR),
csr);
} else {
csr = musb_readw(mbase,
- MUSB_EP_OFFSET(pImplChannel->epnum,
+ MUSB_EP_OFFSET(musb_channel->epnum,
MUSB_RXCSR));
csr &= ~(MUSB_RXCSR_AUTOCLEAR |
MUSB_RXCSR_DMAENAB |
MUSB_RXCSR_DMAMODE);
musb_writew(mbase,
- MUSB_EP_OFFSET(pImplChannel->epnum,
- MUSB_RXCSR),
+ MUSB_EP_OFFSET(musb_channel->epnum, MUSB_RXCSR),
csr);
}
musb_writew(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL),
0);
musb_writel(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS),
0);
musb_writel(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT),
0);
- pChannel->status = MUSB_DMA_STATUS_FREE;
+ channel->status = MUSB_DMA_STATUS_FREE;
}
+
return 0;
}
static irqreturn_t dma_controller_irq(int irq, void *private_data)
{
- struct musb_dma_controller *controller =
- (struct musb_dma_controller *)private_data;
- struct musb_dma_channel *pImplChannel;
- struct musb *musb = controller->pDmaPrivate;
- void __iomem *mbase = controller->pCoreBase;
- struct dma_channel *pChannel;
- u8 bChannel;
- u16 csr;
- u32 dwAddress;
- u8 int_hsdma;
+ struct musb_dma_controller *controller = private_data;
+ struct musb *musb = controller->private_data;
+ struct musb_dma_channel *musb_channel;
+ struct dma_channel *channel;
+
+ void __iomem *mbase = controller->base;
+
irqreturn_t retval = IRQ_NONE;
+
unsigned long flags;
+ u8 bchannel;
+ u8 int_hsdma;
+
+ u32 addr;
+ u16 csr;
+
spin_lock_irqsave(&musb->lock, flags);
int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
if (!int_hsdma)
goto done;
- for (bChannel = 0; bChannel < MUSB_HSDMA_CHANNELS; bChannel++) {
- if (int_hsdma & (1 << bChannel)) {
- pImplChannel = (struct musb_dma_channel *)
- &(controller->aChannel[bChannel]);
- pChannel = &pImplChannel->Channel;
+ for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
+ if (int_hsdma & (1 << bchannel)) {
+ musb_channel = (struct musb_dma_channel *)
+ &(controller->channel[bchannel]);
+ channel = &musb_channel->channel;
csr = musb_readw(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bChannel,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel,
MUSB_HSDMA_CONTROL));
- if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT))
- pImplChannel->Channel.status =
+ if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT)) {
+ musb_channel->channel.status =
MUSB_DMA_STATUS_BUS_ABORT;
- else {
+ } else {
u8 devctl;
- dwAddress = musb_readl(mbase,
+ addr = musb_readl(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(
- bChannel,
+ bchannel,
MUSB_HSDMA_ADDRESS));
- pChannel->actual_len = dwAddress
- - pImplChannel->dwStartAddress;
+ channel->actual_len = addr
+ - musb_channel->start_addr;
DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
- pChannel, pImplChannel->dwStartAddress,
- dwAddress, pChannel->actual_len,
- pImplChannel->len,
- (pChannel->actual_len
- < pImplChannel->len) ?
+ channel, musb_channel->start_addr,
+ addr, channel->actual_len,
+ musb_channel->len,
+ (channel->actual_len
+ < musb_channel->len) ?
"=> reconfig 0" : "=> complete");
devctl = musb_readb(mbase, MUSB_DEVCTL);
- pChannel->status = MUSB_DMA_STATUS_FREE;
+ channel->status = MUSB_DMA_STATUS_FREE;
/* completed */
if ((devctl & MUSB_DEVCTL_HM)
- && (pImplChannel->transmit)
- && ((pChannel->desired_mode == 0)
- || (pChannel->actual_len &
- (pImplChannel->wMaxPacketSize - 1)))
+ && (musb_channel->transmit)
+ && ((channel->desired_mode == 0)
+ || (channel->actual_len &
+ (musb_channel->max_packet_sz - 1)))
) {
/* Send out the packet */
musb_ep_select(mbase,
- pImplChannel->epnum);
+ musb_channel->epnum);
musb_writew(mbase, MUSB_EP_OFFSET(
- pImplChannel->epnum,
+ musb_channel->epnum,
MUSB_TXCSR),
MUSB_TXCSR_TXPKTRDY);
- } else
+ } else {
musb_dma_completion(
musb,
- pImplChannel->epnum,
- pImplChannel->transmit);
+ musb_channel->epnum,
+ musb_channel->transmit);
+ }
}
}
}
@@ -380,9 +383,9 @@ done:
void dma_controller_destroy(struct dma_controller *c)
{
- struct musb_dma_controller *controller;
+ struct musb_dma_controller *controller = container_of(c,
+ struct musb_dma_controller, controller);
- controller = container_of(c, struct musb_dma_controller, Controller);
if (!controller)
return;
@@ -393,7 +396,7 @@ void dma_controller_destroy(struct dma_controller *c)
}
struct dma_controller *__init
-dma_controller_create(struct musb *musb, void __iomem *pCoreBase)
+dma_controller_create(struct musb *musb, void __iomem *base)
{
struct musb_dma_controller *controller;
struct device *dev = musb->controller;
@@ -405,29 +408,30 @@ dma_controller_create(struct musb *musb, void __iomem *pCoreBase)
return NULL;
}
- controller = kzalloc(sizeof(struct musb_dma_controller), GFP_KERNEL);
+ controller = kzalloc(sizeof(*controller), GFP_KERNEL);
if (!controller)
return NULL;
- controller->bChannelCount = MUSB_HSDMA_CHANNELS;
- controller->pDmaPrivate = musb;
- controller->pCoreBase = pCoreBase;
+ controller->channel_count = MUSB_HSDMA_CHANNELS;
+ controller->private_data = musb;
+ controller->base = base;
- controller->Controller.start = dma_controller_start;
- controller->Controller.stop = dma_controller_stop;
- controller->Controller.channel_alloc = dma_channel_allocate;
- controller->Controller.channel_release = dma_channel_release;
- controller->Controller.channel_program = dma_channel_program;
- controller->Controller.channel_abort = dma_channel_abort;
+ controller->controller.start = dma_controller_start;
+ controller->controller.stop = dma_controller_stop;
+ controller->controller.channel_alloc = dma_channel_allocate;
+ controller->controller.channel_release = dma_channel_release;
+ controller->controller.channel_program = dma_channel_program;
+ controller->controller.channel_abort = dma_channel_abort;
if (request_irq(irq, dma_controller_irq, IRQF_DISABLED,
- musb->controller->bus_id, &controller->Controller)) {
+ musb->controller->bus_id, &controller->controller)) {
dev_err(dev, "request_irq %d failed!\n", irq);
- dma_controller_destroy(&controller->Controller);
+ dma_controller_destroy(&controller->controller);
+
return NULL;
}
controller->irq = irq;
- return &controller->Controller;
+ return &controller->controller;
}
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 99fb7dc59c4..537f953bd7f 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -220,8 +220,8 @@ static void aircable_send(struct usb_serial_port *port)
buf = kzalloc(count + HCI_HEADER_LENGTH, GFP_ATOMIC);
if (!buf) {
- err("%s- kzalloc(%d) failed.", __func__,
- count + HCI_HEADER_LENGTH);
+ dev_err(&port->dev, "%s- kzalloc(%d) failed.\n",
+ __func__, count + HCI_HEADER_LENGTH);
return;
}
@@ -276,7 +276,7 @@ static void aircable_read(struct work_struct *work)
if (!tty) {
schedule_work(&priv->rx_work);
- err("%s - No tty available", __func__);
+ dev_err(&port->dev, "%s - No tty available\n", __func__);
return ;
}
@@ -336,7 +336,7 @@ static int aircable_attach(struct usb_serial *serial)
priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
if (!priv) {
- err("%s- kmalloc(%Zd) failed.", __func__,
+ dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
sizeof(struct aircable_private));
return -ENOMEM;
}
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 1913bc7c5f0..b7eacad4d48 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -187,7 +187,7 @@ static int belkin_sa_startup(struct usb_serial *serial)
/* see comments at top of file */
priv->bad_flow_control =
(le16_to_cpu(dev->descriptor.bcdDevice) <= 0x0206) ? 1 : 0;
- info("bcdDevice: %04x, bfc: %d",
+ dev_info(&dev->dev, "bcdDevice: %04x, bfc: %d\n",
le16_to_cpu(dev->descriptor.bcdDevice),
priv->bad_flow_control);
@@ -228,7 +228,7 @@ static int belkin_sa_open(struct tty_struct *tty,
port->read_urb->dev = port->serial->dev;
retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (retval) {
- err("usb_submit_urb(read bulk) failed");
+ dev_err(&port->dev, "usb_submit_urb(read bulk) failed\n");
goto exit;
}
@@ -236,7 +236,7 @@ static int belkin_sa_open(struct tty_struct *tty,
retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (retval) {
usb_kill_urb(port->read_urb);
- err(" usb_submit_urb(read int) failed");
+ dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
}
exit:
@@ -342,8 +342,8 @@ static void belkin_sa_read_int_callback(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(&port->dev, "%s - usb_submit_urb failed with "
+ "result %d\n", __func__, retval);
}
static void belkin_sa_set_termios(struct tty_struct *tty,
@@ -382,12 +382,12 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
if ((old_cflag & CBAUD) == B0) {
control_state |= (TIOCM_DTR|TIOCM_RTS);
if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0)
- err("Set DTR error");
+ dev_err(&port->dev, "Set DTR error\n");
/* don't set RTS if using hardware flow control */
if (!(old_cflag & CRTSCTS))
if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST
, 1) < 0)
- err("Set RTS error");
+ dev_err(&port->dev, "Set RTS error\n");
}
}
@@ -403,18 +403,18 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
/* Report the actual baud rate back to the caller */
tty_encode_baud_rate(tty, baud, baud);
if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
- err("Set baudrate error");
+ dev_err(&port->dev, "Set baudrate error\n");
} else {
/* Disable flow control */
if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST,
BELKIN_SA_FLOW_NONE) < 0)
- err("Disable flowcontrol error");
+ dev_err(&port->dev, "Disable flowcontrol error\n");
/* Drop RTS and DTR */
control_state &= ~(TIOCM_DTR | TIOCM_RTS);
if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
- err("DTR LOW error");
+ dev_err(&port->dev, "DTR LOW error\n");
if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
- err("RTS LOW error");
+ dev_err(&port->dev, "RTS LOW error\n");
}
/* set the parity */
@@ -425,7 +425,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
else
urb_value = BELKIN_SA_PARITY_NONE;
if (BSA_USB_CMD(BELKIN_SA_SET_PARITY_REQUEST, urb_value) < 0)
- err("Set parity error");
+ dev_err(&port->dev, "Set parity error\n");
}
/* set the number of data bits */
@@ -448,7 +448,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
break;
}
if (BSA_USB_CMD(BELKIN_SA_SET_DATA_BITS_REQUEST, urb_value) < 0)
- err("Set data bits error");
+ dev_err(&port->dev, "Set data bits error\n");
}
/* set the number of stop bits */
@@ -457,7 +457,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
: BELKIN_SA_STOP_BITS(1);
if (BSA_USB_CMD(BELKIN_SA_SET_STOP_BITS_REQUEST,
urb_value) < 0)
- err("Set stop bits error");
+ dev_err(&port->dev, "Set stop bits error\n");
}
/* Set flow control */
@@ -478,7 +478,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
urb_value &= ~(BELKIN_SA_FLOW_IRTS);
if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0)
- err("Set flow control error");
+ dev_err(&port->dev, "Set flow control error\n");
}
/* save off the modified port settings */
@@ -494,7 +494,7 @@ static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state)
struct usb_serial *serial = port->serial;
if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0)
- err("Set break_ctl %d", break_state);
+ dev_err(&port->dev, "Set break_ctl %d\n", break_state);
}
@@ -554,13 +554,13 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, struct file *file,
retval = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, rts);
if (retval < 0) {
- err("Set RTS error %d", retval);
+ dev_err(&port->dev, "Set RTS error %d\n", retval);
goto exit;
}
retval = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, dtr);
if (retval < 0) {
- err("Set DTR error %d", retval);
+ dev_err(&port->dev, "Set DTR error %d\n", retval);
goto exit;
}
exit:
@@ -577,7 +577,8 @@ static int __init belkin_sa_init(void)
retval = usb_register(&belkin_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&belkin_device);
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 1279553381e..8008d0bc80a 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -753,7 +753,8 @@ static int __init cp2101_init(void)
}
/* Success */
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
}
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 94ef36c4764..858bdd038fb 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -141,7 +141,8 @@ static int cyberjack_startup(struct usb_serial *serial)
result = usb_submit_urb(serial->port[i]->interrupt_in_urb,
GFP_KERNEL);
if (result)
- err(" usb_submit_urb(read int) failed");
+ dev_err(&serial->dev->dev,
+ "usb_submit_urb(read int) failed\n");
dbg("%s - usb_submit_urb(int urb)", __func__);
}
@@ -274,8 +275,9 @@ static int cyberjack_write(struct tty_struct *tty,
/* send the data out the bulk port */
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d",
+ __func__, result);
/* Throw away data. No better idea what to do with it. */
priv->wrfilled = 0;
priv->wrsent = 0;
@@ -351,7 +353,9 @@ static void cyberjack_read_int_callback(struct urb *urb)
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d", __func__, result);
+ dev_err(&port->dev, "%s - failed resubmitting "
+ "read urb, error %d\n",
+ __func__, result);
dbg("%s - usb_submit_urb(read urb)", __func__);
}
}
@@ -360,7 +364,7 @@ resubmit:
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
- err(" usb_submit_urb(read int) failed");
+ dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
dbg("%s - usb_submit_urb(int urb)", __func__);
}
@@ -414,8 +418,8 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev, "%s - failed resubmitting read "
+ "urb, error %d\n", __func__, result);
dbg("%s - usb_submit_urb(read urb)", __func__);
}
}
@@ -462,8 +466,9 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
/* send the data out the bulk port */
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, result);
/* Throw away data. No better idea what to do with it. */
priv->wrfilled = 0;
priv->wrsent = 0;
@@ -499,8 +504,9 @@ static int __init cyberjack_init(void)
if (retval)
goto failed_usb_register;
- info(DRIVER_VERSION " " DRIVER_AUTHOR);
- info(DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION " "
+ DRIVER_AUTHOR "\n");
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return 0;
failed_usb_register:
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index f3514a91f91..eae4740d448 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -404,8 +404,8 @@ static int cypress_serial_control(struct tty_struct *tty,
retval != -ENODEV);
if (retval != sizeof(feature_buffer)) {
- err("%s - failed sending serial line settings - %d",
- __func__, retval);
+ dev_err(&port->dev, "%s - failed sending serial "
+ "line settings - %d\n", __func__, retval);
cypress_set_dead(port);
} else {
spin_lock_irqsave(&priv->lock, flags);
@@ -443,7 +443,8 @@ static int cypress_serial_control(struct tty_struct *tty,
&& retval != -ENODEV);
if (retval != sizeof(feature_buffer)) {
- err("%s - failed to retrieve serial line settings - %d", __func__, retval);
+ dev_err(&port->dev, "%s - failed to retrieve serial "
+ "line settings - %d\n", __func__, retval);
cypress_set_dead(port);
return retval;
} else {
@@ -476,8 +477,8 @@ static void cypress_set_dead(struct usb_serial_port *port)
priv->comm_is_ok = 0;
spin_unlock_irqrestore(&priv->lock, flags);
- err("cypress_m8 suspending failing port %d - interval might be too short",
- port->number);
+ dev_err(&port->dev, "cypress_m8 suspending failing port %d - "
+ "interval might be too short\n", port->number);
}
@@ -679,7 +680,8 @@ static int cypress_open(struct tty_struct *tty,
/* setup the port and start reading from the device */
if (!port->interrupt_in_urb) {
- err("%s - interrupt_in_urb is empty!", __func__);
+ dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n",
+ __func__);
return -1;
}
@@ -1107,8 +1109,8 @@ static void cypress_set_termios(struct tty_struct *tty,
data_bits = 3;
break;
default:
- err("%s - CSIZE was set, but not CS5-CS8",
- __func__);
+ dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n",
+ __func__);
data_bits = 3;
}
spin_lock_irqsave(&priv->lock, flags);
@@ -1658,7 +1660,8 @@ static int __init cypress_init(void)
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 5756ac6d6c9..69f84f0ea6f 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -661,7 +661,8 @@ static int digi_write_oob_command(struct usb_serial_port *port,
}
spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
if (ret)
- err("%s: usb_submit_urb failed, ret=%d", __func__, ret);
+ dev_err(&port->dev, "%s: usb_submit_urb failed, ret=%d\n",
+ __func__, ret);
return ret;
}
@@ -743,7 +744,8 @@ static int digi_write_inb_command(struct usb_serial_port *port,
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
if (ret)
- err("%s: usb_submit_urb failed, ret=%d, port=%d",
+ dev_err(&port->dev,
+ "%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
return ret;
}
@@ -812,7 +814,8 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
spin_unlock(&port_priv->dp_port_lock);
spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
if (ret)
- err("%s: usb_submit_urb failed, ret=%d", __func__, ret);
+ dev_err(&port->dev, "%s: usb_submit_urb failed, ret=%d\n",
+ __func__, ret);
return ret;
}
@@ -907,7 +910,8 @@ static void digi_rx_unthrottle(struct tty_struct *tty)
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
if (ret)
- err("%s: usb_submit_urb failed, ret=%d, port=%d",
+ dev_err(&port->dev,
+ "%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
}
@@ -1214,7 +1218,8 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
/* return length of new data written, or error */
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
if (ret < 0)
- err("%s: usb_submit_urb failed, ret=%d, port=%d",
+ dev_err(&port->dev,
+ "%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
dbg("digi_write: returning %d", ret);
return ret;
@@ -1235,14 +1240,16 @@ static void digi_write_bulk_callback(struct urb *urb)
/* port and serial sanity check */
if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
- err("%s: port or port->private is NULL, status=%d",
- __func__, status);
+ dev_err(&port->dev,
+ "%s: port or port->private is NULL, status=%d\n",
+ __func__, status);
return;
}
serial = port->serial;
if (serial == NULL || (serial_priv = usb_get_serial_data(serial)) == NULL) {
- err("%s: serial or serial->private is NULL, status=%d",
- __func__, status);
+ dev_err(&port->dev,
+ "%s: serial or serial->private is NULL, status=%d\n",
+ __func__, status);
return;
}
@@ -1284,7 +1291,8 @@ static void digi_write_bulk_callback(struct urb *urb)
spin_unlock(&priv->dp_port_lock);
if (ret)
- err("%s: usb_submit_urb failed, ret=%d, port=%d",
+ dev_err(&port->dev,
+ "%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
}
@@ -1518,8 +1526,9 @@ static int digi_startup_device(struct usb_serial *serial)
port->write_urb->dev = port->serial->dev;
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (ret != 0) {
- err("%s: usb_submit_urb failed, ret=%d, port=%d",
- __func__, ret, i);
+ dev_err(&port->dev,
+ "%s: usb_submit_urb failed, ret=%d, port=%d\n",
+ __func__, ret, i);
break;
}
}
@@ -1618,22 +1627,26 @@ static void digi_read_bulk_callback(struct urb *urb)
dbg("digi_read_bulk_callback: TOP");
/* port sanity check, do not resubmit if port is not valid */
- if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
- err("%s: port or port->private is NULL, status=%d",
- __func__, status);
+ if (port == NULL)
+ return;
+ priv = usb_get_serial_port_data(port);
+ if (priv == NULL) {
+ dev_err(&port->dev, "%s: port->private is NULL, status=%d\n",
+ __func__, status);
return;
}
if (port->serial == NULL ||
(serial_priv = usb_get_serial_data(port->serial)) == NULL) {
- err("%s: serial is bad or serial->private is NULL, status=%d",
- __func__, status);
+ dev_err(&port->dev, "%s: serial is bad or serial->private "
+ "is NULL, status=%d\n", __func__, status);
return;
}
/* do not resubmit urb if it has any status error */
if (status) {
- err("%s: nonzero read bulk status: status=%d, port=%d",
- __func__, status, priv->dp_port_num);
+ dev_err(&port->dev,
+ "%s: nonzero read bulk status: status=%d, port=%d\n",
+ __func__, status, priv->dp_port_num);
return;
}
@@ -1650,8 +1663,9 @@ static void digi_read_bulk_callback(struct urb *urb)
urb->dev = port->serial->dev;
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret != 0) {
- err("%s: failed resubmitting urb, ret=%d, port=%d",
- __func__, ret, priv->dp_port_num);
+ dev_err(&port->dev,
+ "%s: failed resubmitting urb, ret=%d, port=%d\n",
+ __func__, ret, priv->dp_port_num);
}
}
@@ -1687,10 +1701,11 @@ static int digi_read_inb_callback(struct urb *urb)
/* short/multiple packet check */
if (urb->actual_length != len + 2) {
- err("%s: INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, "
- "port=%d, opcode=%d, len=%d, actual_length=%d, "
- "status=%d", __func__, status, priv->dp_port_num,
- opcode, len, urb->actual_length, port_status);
+ dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, "
+ "urb->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);
return -1;
}
@@ -1854,7 +1869,8 @@ static int __init digi_init(void)
retval = usb_register(&digi_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&digi_acceleport_4_device);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 1072e847280..8a69cce40b6 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -416,7 +416,7 @@ static int empeg_startup(struct usb_serial *serial)
dbg("%s", __func__);
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
- err("active config #%d != 1 ??",
+ dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
serial->dev->actconfig->desc.bConfigurationValue);
return -ENODEV;
}
@@ -499,15 +499,15 @@ static int __init empeg_init(void)
urb = usb_alloc_urb(0, GFP_KERNEL);
write_urb_pool[i] = urb;
if (urb == NULL) {
- err("No more urbs???");
+ printk(KERN_ERR "empeg: No more urbs???\n");
continue;
}
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (!urb->transfer_buffer) {
- err("%s - out of memory for urb buffers.",
- __func__);
+ printk(KERN_ERR "empeg: %s - out of memory for urb "
+ "buffers.", __func__);
continue;
}
}
@@ -519,7 +519,8 @@ static int __init empeg_init(void)
if (retval)
goto failed_usb_register;
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index 711e84f6ed8..3cfc762f505 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -28,7 +28,8 @@ int ezusb_writememory(struct usb_serial *serial, int address,
/* dbg("ezusb_writememory %x, %d", address, length); */
if (!serial->dev) {
- err("%s - no physical device present, failing.", __func__);
+ printk(KERN_ERR "ezusb: %s - no physical device present, "
+ "failing.\n", __func__);
return -ENODEV;
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c2ac129557a..51d7bdea286 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -578,6 +578,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
{ USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
{ USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
@@ -1153,7 +1154,7 @@ static void ftdi_determine_type(struct usb_serial_port *port)
/* Assume its an FT232R */
priv->chip_type = FT232RL;
}
- info("Detected %s", ftdi_chip_name[priv->chip_type]);
+ dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
}
@@ -1326,7 +1327,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv) {
- err("%s- kmalloc(%Zd) failed.", __func__,
+ dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
sizeof(struct ftdi_private));
return -ENOMEM;
}
@@ -1409,7 +1410,8 @@ static int ftdi_jtag_probe(struct usb_serial *serial)
dbg("%s", __func__);
if (interface == udev->actconfig->interface[0]) {
- info("Ignoring serial port reserved for JTAG");
+ dev_info(&udev->dev,
+ "Ignoring serial port reserved for JTAG\n");
return -ENODEV;
}
@@ -1427,7 +1429,8 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
if (ep->enabled && ep_desc->wMaxPacketSize == 0) {
ep_desc->wMaxPacketSize = cpu_to_le16(0x40);
- info("Fixing invalid wMaxPacketSize on read pipe");
+ dev_info(&serial->dev->dev,
+ "Fixing invalid wMaxPacketSize on read pipe\n");
}
return 0;
@@ -1521,8 +1524,9 @@ static int ftdi_open(struct tty_struct *tty,
ftdi_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
- err("%s - failed submitting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __func__, result);
return result;
@@ -1556,7 +1560,7 @@ static void ftdi_close(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, buf, 0,
WDR_TIMEOUT) < 0) {
- err("error from flowcontrol urb");
+ dev_err(&port->dev, "error from flowcontrol urb\n");
}
/* drop RTS and DTR */
@@ -1621,14 +1625,15 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
buffer = kmalloc(transfer_size, GFP_ATOMIC);
if (!buffer) {
- err("%s ran out of kernel memory for urb ...", __func__);
+ dev_err(&port->dev,
+ "%s ran out of kernel memory for urb ...\n", __func__);
count = -ENOMEM;
goto error_no_buffer;
}
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- err("%s - no more free urbs", __func__);
+ dev_err(&port->dev, "%s - no more free urbs\n", __func__);
count = -ENOMEM;
goto error_no_urb;
}
@@ -1672,8 +1677,9 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
- err("%s - failed submitting write urb, error %d",
- __func__, status);
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, status);
count = status;
goto error;
} else {
@@ -1780,7 +1786,8 @@ static int ftdi_chars_in_buffer(struct tty_struct *tty)
buffered = (int)priv->tx_outstanding_bytes;
spin_unlock_irqrestore(&priv->tx_lock, flags);
if (buffered < 0) {
- err("%s outstanding tx bytes is negative!", __func__);
+ dev_err(&port->dev, "%s outstanding tx bytes is negative!\n",
+ __func__);
buffered = 0;
}
return buffered;
@@ -1796,11 +1803,12 @@ static void ftdi_read_bulk_callback(struct urb *urb)
int status = urb->status;
if (urb->number_of_packets > 0) {
- err("%s transfer_buffer_length %d actual_length %d number of packets %d",
- __func__,
- urb->transfer_buffer_length,
- urb->actual_length, urb->number_of_packets);
- err("%s transfer_flags %x ", __func__, urb->transfer_flags);
+ dev_err(&port->dev, "%s transfer_buffer_length %d "
+ "actual_length %d number of packets %d\n", __func__,
+ urb->transfer_buffer_length,
+ urb->actual_length, urb->number_of_packets);
+ dev_err(&port->dev, "%s transfer_flags %x\n", __func__,
+ urb->transfer_flags);
}
dbg("%s - port %d", __func__, port->number);
@@ -1821,7 +1829,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
}
if (urb != port->read_urb)
- err("%s - Not my urb!", __func__);
+ dev_err(&port->dev, "%s - Not my urb!\n", __func__);
if (status) {
/* This will happen at close every time so it is a dbg not an
@@ -1924,7 +1932,8 @@ static void ftdi_process_read(struct work_struct *work)
length = min(PKTSZ, urb->actual_length-packet_offset)-2;
if (length < 0) {
- err("%s - bad packet length: %d", __func__, length+2);
+ dev_err(&port->dev, "%s - bad packet length: %d\n",
+ __func__, length+2);
length = 0;
}
@@ -2039,8 +2048,9 @@ static void ftdi_process_read(struct work_struct *work)
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __func__, result);
}
out:
tty_kref_put(tty);
@@ -2069,8 +2079,8 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
- err("%s FAILED to enable/disable break state (state was %d)",
- __func__, break_state);
+ dev_err(&port->dev, "%s FAILED to enable/disable break state "
+ "(state was %d)\n", __func__, break_state);
}
dbg("%s break state is %d - urb is %d", __func__,
@@ -2142,7 +2152,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
case CS7: urb_value |= 7; dbg("Setting CS7"); break;
case CS8: urb_value |= 8; dbg("Setting CS8"); break;
default:
- err("CSIZE was set but not CS5-CS8");
+ dev_err(&port->dev, "CSIZE was set but not CS5-CS8\n");
}
}
@@ -2155,7 +2165,8 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_SHORT_TIMEOUT) < 0) {
- err("%s FAILED to set databits/stopbits/parity", __func__);
+ dev_err(&port->dev, "%s FAILED to set "
+ "databits/stopbits/parity\n", __func__);
}
/* Now do the baudrate */
@@ -2166,14 +2177,17 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
- err("%s error from disable flowcontrol urb", __func__);
+ dev_err(&port->dev,
+ "%s error from disable flowcontrol urb\n",
+ __func__);
}
/* Drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} else {
/* set the baudrate determined before */
if (change_speed(tty, port))
- err("%s urb failed to set baudrate", __func__);
+ dev_err(&port->dev, "%s urb failed to set baudrate\n",
+ __func__);
/* Ensure RTS and DTR are raised when baudrate changed from 0 */
if (!old_termios || (old_termios->c_cflag & CBAUD) == B0)
set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
@@ -2189,7 +2203,8 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
buf, 0, WDR_TIMEOUT) < 0) {
- err("urb failed to set to rts/cts flow control");
+ dev_err(&port->dev,
+ "urb failed to set to rts/cts flow control\n");
}
} else {
@@ -2220,7 +2235,8 @@ static void ftdi_set_termios(struct tty_struct *tty,
urb_value , (FTDI_SIO_XON_XOFF_HS
| priv->interface),
buf, 0, WDR_TIMEOUT) < 0) {
- err("urb failed to set to xon/xoff flow control");
+ dev_err(&port->dev, "urb failed to set to "
+ "xon/xoff flow control\n");
}
} else {
/* else clause to only run if cflag ! CRTSCTS and iflag
@@ -2233,7 +2249,8 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
- err("urb failed to clear flow control");
+ dev_err(&port->dev,
+ "urb failed to clear flow control\n");
}
}
@@ -2425,7 +2442,8 @@ static int __init ftdi_init(void)
if (retval)
goto failed_usb_register;
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&ftdi_sio_device);
@@ -2458,5 +2476,5 @@ module_param(vendor, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
__MODULE_STRING(FTDI_VID)")");
module_param(product, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified product ID");
+MODULE_PARM_DESC(product, "User specified product ID");
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 8a5b6df3a97..07a3992abad 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -628,6 +628,11 @@
#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */
/*
+ * Oceanic product ids
+ */
+#define FTDI_OCEANIC_PID 0xF460 /* Oceanic dive instrument */
+
+/*
* TTi (Thurlby Thandar Instruments)
*/
#define TTI_VID 0x103E /* Vendor Id */
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 2ad0569bcf1..8e6a66e38db 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1585,7 +1585,8 @@ static int __init garmin_init(void)
retval = usb_register(&garmin_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index ab905869e95..43132927513 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -63,7 +63,8 @@ static int __init hp49gp_init(void)
retval = usb_register(&hp49gp_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&hp49gp_device);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 611f97fd62f..e85c8c0d1ad 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -3109,13 +3109,13 @@ static int edge_startup(struct usb_serial *serial)
edge_serial->interrupt_read_urb =
usb_alloc_urb(0, GFP_KERNEL);
if (!edge_serial->interrupt_read_urb) {
- err("out of memory");
+ dev_err(&dev->dev, "out of memory\n");
return -ENOMEM;
}
edge_serial->interrupt_in_buffer =
kmalloc(buffer_size, GFP_KERNEL);
if (!edge_serial->interrupt_in_buffer) {
- err("out of memory");
+ dev_err(&dev->dev, "out of memory\n");
usb_free_urb(edge_serial->interrupt_read_urb);
return -ENOMEM;
}
@@ -3146,13 +3146,13 @@ static int edge_startup(struct usb_serial *serial)
edge_serial->read_urb =
usb_alloc_urb(0, GFP_KERNEL);
if (!edge_serial->read_urb) {
- err("out of memory");
+ dev_err(&dev->dev, "out of memory\n");
return -ENOMEM;
}
edge_serial->bulk_in_buffer =
kmalloc(buffer_size, GFP_KERNEL);
if (!edge_serial->bulk_in_buffer) {
- err("out of memory");
+ dev_err(&dev->dev, "out of memory\n");
usb_free_urb(edge_serial->read_urb);
return -ENOMEM;
}
@@ -3181,7 +3181,8 @@ static int edge_startup(struct usb_serial *serial)
}
if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) {
- err("Error - the proper endpoints were not found!");
+ dev_err(&dev->dev, "Error - the proper endpoints "
+ "were not found!\n");
return -ENODEV;
}
@@ -3190,8 +3191,9 @@ static int edge_startup(struct usb_serial *serial)
response = usb_submit_urb(edge_serial->interrupt_read_urb,
GFP_KERNEL);
if (response)
- err("%s - Error %d submitting control urb",
- __func__, response);
+ dev_err(&dev->dev,
+ "%s - Error %d submitting control urb\n",
+ __func__, response);
}
return response;
}
@@ -3253,7 +3255,8 @@ static int __init edgeport_init(void)
if (retval)
goto failed_usb_register;
atomic_set(&CmdUrbs, 0);
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 541dd8e6e7a..c3cdd00ddc4 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2978,7 +2978,8 @@ static int __init edgeport_init(void)
retval = usb_register(&io_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&edgeport_2port_device);
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 2affa9c118b..132be74d2b8 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -608,7 +608,7 @@ static int ipaq_open(struct tty_struct *tty,
bytes_out = 0;
priv = kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
if (priv == NULL) {
- err("%s - Out of memory", __func__);
+ dev_err(&port->dev, "%s - Out of memory\n", __func__);
return -ENOMEM;
}
usb_set_serial_port_data(port, priv);
@@ -693,8 +693,7 @@ static int ipaq_open(struct tty_struct *tty,
}
if (!retries && result) {
- err("%s - failed doing control urb, error %d", __func__,
- result);
+ dev_err(&port->dev, "%s - failed doing control urb, error %d\n", __func__, result);
goto error;
}
@@ -707,8 +706,9 @@ static int ipaq_open(struct tty_struct *tty,
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) {
- err("%s - failed submitting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __func__, result);
goto error;
}
@@ -716,7 +716,7 @@ static int ipaq_open(struct tty_struct *tty,
enomem:
result = -ENOMEM;
- err("%s - Out of memory", __func__);
+ dev_err(&port->dev, "%s - Out of memory\n", __func__);
error:
ipaq_destroy_lists(port);
kfree(priv);
@@ -781,8 +781,9 @@ static void ipaq_read_bulk_callback(struct urb *urb)
ipaq_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __func__, result);
return;
}
@@ -847,7 +848,8 @@ static int ipaq_write_bulk(struct usb_serial_port *port,
spin_unlock_irqrestore(&write_list_lock, flags);
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
- err("%s - failed submitting write urb, error %d",
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
__func__, result);
} else {
spin_unlock_irqrestore(&write_list_lock, flags);
@@ -909,8 +911,9 @@ static void ipaq_write_bulk_callback(struct urb *urb)
spin_unlock_irqrestore(&write_list_lock, flags);
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
- err("%s - failed submitting write urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, result);
} else {
priv->active = 0;
spin_unlock_irqrestore(&write_list_lock, flags);
@@ -957,7 +960,7 @@ static int ipaq_startup(struct usb_serial *serial)
{
dbg("%s", __func__);
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
- err("active config #%d != 1 ??",
+ dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
serial->dev->actconfig->desc.bConfigurationValue);
return -ENODEV;
}
@@ -976,7 +979,6 @@ static int __init ipaq_init(void)
retval = usb_serial_register(&ipaq_device);
if (retval)
goto failed_usb_serial_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
if (vendor) {
ipaq_id_table[0].idVendor = vendor;
ipaq_id_table[0].idProduct = product;
@@ -985,6 +987,8 @@ static int __init ipaq_init(void)
if (retval)
goto failed_usb_register;
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&ipaq_device);
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 480cac27d64..3ac59a8a980 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -485,7 +485,8 @@ static int usb_ipw_init(void)
usb_serial_deregister(&ipw_device);
return retval;
}
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
}
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 45d4043e04a..b679a556b98 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -602,7 +602,8 @@ static int __init ir_init(void)
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 53710aa7ead..e320972cb22 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -1185,7 +1185,8 @@ static int __init iuu_init(void)
retval = usb_register(&iuu_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&iuu_device);
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 15447af4869..9878c0fb385 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -217,7 +217,8 @@ static int __init keyspan_init(void)
if (retval)
goto failed_usb_register;
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 99e9a14c5bf..bf1ae247da6 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -742,11 +742,13 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial)
fw_name = "keyspan_pda/xircom_pgs.fw";
#endif
else {
- err("%s: unknown vendor, aborting.", __func__);
+ dev_err(&serial->dev->dev, "%s: unknown vendor, aborting.\n",
+ __func__);
return -ENODEV;
}
if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
- err("failed to load firmware \"%s\"\n", fw_name);
+ dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
+ fw_name);
return -ENOENT;
}
record = (const struct ihex_binrec *)fw->data;
@@ -756,10 +758,10 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial)
(unsigned char *)record->data,
be16_to_cpu(record->len), 0xa0);
if (response < 0) {
- err("ezusb_writememory failed for Keyspan PDA "
- "firmware (%d %04X %p %d)",
- response, be32_to_cpu(record->addr),
- record->data, be16_to_cpu(record->len));
+ dev_err(&serial->dev->dev, "ezusb_writememory failed "
+ "for Keyspan PDA firmware (%d %04X %p %d)\n",
+ response, be32_to_cpu(record->addr),
+ record->data, be16_to_cpu(record->len));
break;
}
record = ihex_next_binrec(record);
@@ -874,7 +876,8 @@ static int __init keyspan_pda_init(void)
retval = usb_register(&keyspan_pda_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
#ifdef XIRCOM
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index ff3a07f5102..dc36a052766 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -182,12 +182,12 @@ static int klsi_105_chg_port_settings(struct usb_serial_port *port,
sizeof(struct klsi_105_port_settings),
KLSI_TIMEOUT);
if (rc < 0)
- err("Change port settings failed (error = %d)", rc);
- info("%s - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d",
- __func__,
- settings->pktlen,
- settings->baudrate, settings->databits,
- settings->unknown1, settings->unknown2);
+ dev_err(&port->dev,
+ "Change port settings failed (error = %d)\n", rc);
+ dev_info(&port->serial->dev->dev,
+ "%d byte block, baudrate %x, databits %d, u1 %d, u2 %d\n",
+ settings->pktlen, settings->baudrate, settings->databits,
+ settings->unknown1, settings->unknown2);
return rc;
} /* klsi_105_chg_port_settings */
@@ -215,7 +215,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
__u8 status_buf[KLSI_STATUSBUF_LEN] = { -1, -1};
__u16 status;
- info("%s - sending SIO Poll request", __func__);
+ dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");
rc = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
KL5KUSB105A_SIO_POLL,
@@ -226,12 +226,13 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
10000
);
if (rc < 0)
- err("Reading line status failed (error = %d)", rc);
+ dev_err(&port->dev, "Reading line status failed (error = %d)\n",
+ rc);
else {
status = get_unaligned_le16(status_buf);
- info("%s - read status %x %x", __func__,
- status_buf[0], status_buf[1]);
+ dev_info(&port->serial->dev->dev, "read status %x %x",
+ status_buf[0], status_buf[1]);
*line_state_p = klsi_105_status2linestate(status);
}
@@ -280,15 +281,16 @@ static int klsi_105_startup(struct usb_serial *serial)
priv->write_urb_pool[j] = urb;
if (urb == NULL) {
- err("No more urbs???");
+ dev_err(&serial->dev->dev, "No more urbs???\n");
goto err_cleanup;
}
urb->transfer_buffer =
kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
if (!urb->transfer_buffer) {
- err("%s - out of memory for urb buffers.",
- __func__);
+ dev_err(&serial->dev->dev,
+ "%s - out of memory for urb buffers.\n",
+ __func__);
goto err_cleanup;
}
}
@@ -409,7 +411,8 @@ static int klsi_105_open(struct tty_struct *tty,
rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (rc) {
- err("%s - failed submitting read urb, error %d", __func__, rc);
+ dev_err(&port->dev, "%s - failed submitting read urb, "
+ "error %d\n", __func__, rc);
retval = rc;
goto exit;
}
@@ -424,7 +427,7 @@ static int klsi_105_open(struct tty_struct *tty,
0,
KLSI_TIMEOUT);
if (rc < 0) {
- err("Enabling read failed (error = %d)", rc);
+ dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
retval = rc;
} else
dbg("%s - enabled reading", __func__);
@@ -464,7 +467,8 @@ static void klsi_105_close(struct tty_struct *tty,
NULL, 0,
KLSI_TIMEOUT);
if (rc < 0)
- err("Disabling read failed (error = %d)", rc);
+ dev_err(&port->dev,
+ "Disabling read failed (error = %d)\n", rc);
}
mutex_unlock(&port->serial->disc_mutex);
@@ -475,8 +479,9 @@ static void klsi_105_close(struct tty_struct *tty,
/* FIXME */
/* wgg - do I need this? I think so. */
usb_kill_urb(port->interrupt_in_urb);
- info("kl5kusb105 port stats: %ld bytes in, %ld bytes out",
- priv->bytes_in, priv->bytes_out);
+ dev_info(&port->serial->dev->dev,
+ "port stats: %ld bytes in, %ld bytes out\n",
+ priv->bytes_in, priv->bytes_out);
} /* klsi_105_close */
@@ -522,7 +527,9 @@ static int klsi_105_write(struct tty_struct *tty,
urb->transfer_buffer =
kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC);
if (urb->transfer_buffer == NULL) {
- err("%s - no more kernel memory...", __func__);
+ dev_err(&port->dev,
+ "%s - no more kernel memory...\n",
+ __func__);
goto exit;
}
}
@@ -549,8 +556,9 @@ static int klsi_105_write(struct tty_struct *tty,
/* send the data out the bulk port */
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, result);
goto exit;
}
buf += size;
@@ -694,8 +702,9 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
port);
rc = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (rc)
- err("%s - failed resubmitting read urb, error %d",
- __func__, rc);
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __func__, rc);
} /* klsi_105_read_bulk_callback */
@@ -799,7 +808,8 @@ static void klsi_105_set_termios(struct tty_struct *tty,
priv->cfg.databits = kl5kusb105a_dtb_8;
break;
default:
- err("CSIZE was not CS5-CS8, using default of 8");
+ dev_err(&port->dev,
+ "CSIZE was not CS5-CS8, using default of 8\n");
priv->cfg.databits = kl5kusb105a_dtb_8;
break;
}
@@ -886,7 +896,8 @@ static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file)
rc = klsi_105_get_line_state(port, &line_state);
if (rc < 0) {
- err("Reading line control failed (error = %d)", rc);
+ dev_err(&port->dev,
+ "Reading line control failed (error = %d)\n", rc);
/* better return value? EAGAIN? */
return rc;
}
@@ -944,8 +955,9 @@ static void klsi_105_unthrottle(struct tty_struct *tty)
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed submitting read urb, error %d", __func__,
- result);
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __func__, result);
}
@@ -960,7 +972,8 @@ static int __init klsi_105_init(void)
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&kl5kusb105d_device);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index cfcf37c2b95..6286baad939 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -744,8 +744,8 @@ static int __init kobil_init(void)
if (retval)
goto failed_usb_register;
- info(DRIVER_VERSION " " DRIVER_AUTHOR);
- info(DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 9b2cef81cde..07710cf31d0 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -246,7 +246,8 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty,
0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
WDR_TIMEOUT);
if (rc < 0) /*FIXME: What value speed results */
- err("Set BAUD RATE %d failed (error = %d)", value, rc);
+ dev_err(&port->dev, "Set BAUD RATE %d failed (error = %d)\n",
+ value, rc);
else
tty_encode_baud_rate(tty, speed, speed);
dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
@@ -274,8 +275,9 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty,
0, 0, &zero_byte, MCT_U232_SET_UNKNOWN1_SIZE,
WDR_TIMEOUT);
if (rc < 0)
- err("Sending USB device request code %d failed (error = %d)",
- MCT_U232_SET_UNKNOWN1_REQUEST, rc);
+ dev_err(&port->dev, "Sending USB device request code %d "
+ "failed (error = %d)\n", MCT_U232_SET_UNKNOWN1_REQUEST,
+ rc);
if (port && C_CRTSCTS(tty))
cts_enable_byte = 1;
@@ -288,8 +290,8 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty,
0, 0, &cts_enable_byte, MCT_U232_SET_CTS_SIZE,
WDR_TIMEOUT);
if (rc < 0)
- err("Sending USB device request code %d failed (error = %d)",
- MCT_U232_SET_CTS_REQUEST, rc);
+ dev_err(&port->dev, "Sending USB device request code %d "
+ "failed (error = %d)\n", MCT_U232_SET_CTS_REQUEST, rc);
return rc;
} /* mct_u232_set_baud_rate */
@@ -303,7 +305,8 @@ static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
0, 0, &lcr, MCT_U232_SET_LINE_CTRL_SIZE,
WDR_TIMEOUT);
if (rc < 0)
- err("Set LINE CTRL 0x%x failed (error = %d)", lcr, rc);
+ dev_err(&serial->dev->dev,
+ "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc);
dbg("set_line_ctrl: 0x%x", lcr);
return rc;
} /* mct_u232_set_line_ctrl */
@@ -325,7 +328,8 @@ static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
0, 0, &mcr, MCT_U232_SET_MODEM_CTRL_SIZE,
WDR_TIMEOUT);
if (rc < 0)
- err("Set MODEM CTRL 0x%x failed (error = %d)", mcr, rc);
+ dev_err(&serial->dev->dev,
+ "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc);
dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
return rc;
@@ -341,7 +345,8 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial,
0, 0, msr, MCT_U232_GET_MODEM_STAT_SIZE,
WDR_TIMEOUT);
if (rc < 0) {
- err("Get MODEM STATus failed (error = %d)", rc);
+ dev_err(&serial->dev->dev,
+ "Get MODEM STATus failed (error = %d)\n", rc);
*msr = 0;
}
dbg("get_modem_stat: 0x%x", *msr);
@@ -470,8 +475,9 @@ static int mct_u232_open(struct tty_struct *tty,
port->read_urb->dev = port->serial->dev;
retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (retval) {
- err("usb_submit_urb(read bulk) failed pipe 0x%x err %d",
- port->read_urb->pipe, retval);
+ dev_err(&port->dev,
+ "usb_submit_urb(read bulk) failed pipe 0x%x err %d\n",
+ port->read_urb->pipe, retval);
goto error;
}
@@ -479,8 +485,9 @@ static int mct_u232_open(struct tty_struct *tty,
retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (retval) {
usb_kill_urb(port->read_urb);
- err(" usb_submit_urb(read int) failed pipe 0x%x err %d",
- port->interrupt_in_urb->pipe, retval);
+ dev_err(&port->dev,
+ "usb_submit_urb(read int) failed pipe 0x%x err %d",
+ port->interrupt_in_urb->pipe, retval);
goto error;
}
return 0;
@@ -612,8 +619,9 @@ static void mct_u232_read_int_callback(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(&port->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
} /* mct_u232_read_int_callback */
static void mct_u232_set_termios(struct tty_struct *tty,
@@ -680,7 +688,8 @@ static void mct_u232_set_termios(struct tty_struct *tty,
case CS8:
last_lcr |= MCT_U232_DATA_BITS_8; break;
default:
- err("CSIZE was not CS5-CS8, using default of 8");
+ dev_err(&port->dev,
+ "CSIZE was not CS5-CS8, using default of 8\n");
last_lcr |= MCT_U232_DATA_BITS_8;
break;
}
@@ -817,7 +826,8 @@ static int __init mct_u232_init(void)
retval = usb_register(&mct_u232_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&mct_u232_device);
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 7b538caec37..e772cc0a97f 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -355,14 +355,16 @@ static int mos7720_open(struct tty_struct *tty,
mos7720_port->write_urb_pool[j] = urb;
if (urb == NULL) {
- err("No more urbs???");
+ dev_err(&port->dev, "No more urbs???\n");
continue;
}
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (!urb->transfer_buffer) {
- err("%s-out of memory for urb buffers.", __func__);
+ dev_err(&port->dev,
+ "%s-out of memory for urb buffers.\n",
+ __func__);
usb_free_urb(mos7720_port->write_urb_pool[j]);
mos7720_port->write_urb_pool[j] = NULL;
continue;
@@ -694,7 +696,8 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (urb->transfer_buffer == NULL) {
- err("%s no more kernel memory...", __func__);
+ dev_err(&port->dev, "%s no more kernel memory...\n",
+ __func__);
goto exit;
}
}
@@ -714,8 +717,8 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
/* send it down the pipe */
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
- err("%s - usb_submit_urb(write bulk) failed with status = %d",
- __func__, status);
+ dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
+ "with status = %d\n", __func__, status);
bytes_sent = status;
goto exit;
}
@@ -975,7 +978,7 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
/* Calculate the Divisor */
status = calc_baud_rate_divisor(baudrate, &divisor);
if (status) {
- err("%s - bad baud rate", __func__);
+ dev_err(&port->dev, "%s - bad baud rate\n", __func__);
return status;
}
@@ -1478,7 +1481,7 @@ static int mos7720_startup(struct usb_serial *serial)
/* create our private serial structure */
mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL);
if (mos7720_serial == NULL) {
- err("%s - Out of memory", __func__);
+ dev_err(&dev->dev, "%s - Out of memory\n", __func__);
return -ENOMEM;
}
@@ -1491,7 +1494,7 @@ static int mos7720_startup(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
if (mos7720_port == NULL) {
- err("%s - Out of memory", __func__);
+ dev_err(&dev->dev, "%s - Out of memory\n", __func__);
usb_set_serial_data(serial, NULL);
kfree(mos7720_serial);
return -ENOMEM;
@@ -1585,7 +1588,8 @@ static int __init moschip7720_init(void)
if (retval)
goto failed_port_device_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
/* Register with the usb */
retval = usb_register(&usb_driver);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 60543d79ef5..fda4a6421c4 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -844,7 +844,7 @@ static int mos7840_open(struct tty_struct *tty,
mos7840_port->write_urb_pool[j] = urb;
if (urb == NULL) {
- err("No more urbs???");
+ dev_err(&port->dev, "No more urbs???\n");
continue;
}
@@ -853,7 +853,9 @@ static int mos7840_open(struct tty_struct *tty,
if (!urb->transfer_buffer) {
usb_free_urb(urb);
mos7840_port->write_urb_pool[j] = NULL;
- err("%s-out of memory for urb buffers.", __func__);
+ dev_err(&port->dev,
+ "%s-out of memory for urb buffers.\n",
+ __func__);
continue;
}
}
@@ -1021,8 +1023,8 @@ static int mos7840_open(struct tty_struct *tty,
usb_submit_urb(serial->port[0]->interrupt_in_urb,
GFP_KERNEL);
if (response) {
- err("%s - Error %d submitting interrupt urb",
- __func__, response);
+ dev_err(&port->dev, "%s - Error %d submitting "
+ "interrupt urb\n", __func__, response);
}
}
@@ -1055,8 +1057,8 @@ static int mos7840_open(struct tty_struct *tty,
port->bulk_in_endpointAddress);
response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
if (response) {
- err("%s - Error %d submitting control urb", __func__,
- response);
+ dev_err(&port->dev, "%s - Error %d submitting control urb\n",
+ __func__, response);
}
/* initialize our wait queues */
@@ -1492,7 +1494,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
if (urb->transfer_buffer == NULL) {
- err("%s no more kernel memory...", __func__);
+ dev_err(&port->dev, "%s no more kernel memory...\n",
+ __func__);
goto exit;
}
}
@@ -1517,8 +1520,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
if (status) {
mos7840_port->busy[i] = 0;
- err("%s - usb_submit_urb(write bulk) failed with status = %d",
- __func__, status);
+ dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
+ "with status = %d\n", __func__, status);
bytes_sent = status;
goto exit;
}
@@ -1856,8 +1859,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
/* Calculate the Divisor */
if (status) {
- err("%s - bad baud rate", __func__);
- dbg("%s\n", "bad baud rate");
+ dev_err(&port->dev, "%s - bad baud rate\n", __func__);
return status;
}
/* Enable access to divisor latch */
@@ -2446,7 +2448,7 @@ static int mos7840_startup(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
if (mos7840_port == NULL) {
- err("%s - Out of memory", __func__);
+ dev_err(&dev->dev, "%s - Out of memory\n", __func__);
status = -ENOMEM;
i--; /* don't follow NULL pointer cleaning up */
goto error;
@@ -2743,7 +2745,8 @@ static int __init moschip7840_init(void)
goto failed_port_device_register;
dbg("%s\n", "Entring...");
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
/* Register with the usb */
retval = usb_register(&io_driver);
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index c4d70b0f1e4..df653971272 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -154,8 +154,8 @@ static int omninet_attach(struct usb_serial *serial)
od = kmalloc(sizeof(struct omninet_data), GFP_KERNEL);
if (!od) {
- err("%s- kmalloc(%Zd) failed.",
- __func__, sizeof(struct omninet_data));
+ dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n",
+ __func__, sizeof(struct omninet_data));
return -ENOMEM;
}
usb_set_serial_port_data(port, od);
@@ -183,8 +183,9 @@ static int omninet_open(struct tty_struct *tty,
omninet_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
- err("%s - failed submitting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __func__, result);
return result;
}
@@ -244,8 +245,9 @@ static void omninet_read_bulk_callback(struct urb *urb)
omninet_read_bulk_callback, port);
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __func__, result);
return;
}
@@ -298,8 +300,9 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
if (result) {
wport->write_urb_busy = 0;
- err("%s - failed submitting write urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, result);
} else
result = count;
@@ -364,7 +367,8 @@ static int __init omninet_init(void)
retval = usb_register(&omninet_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&zyxel_omninet_device);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 6b1727e751e..bd07eaa300b 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -79,38 +79,36 @@ static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *po
#define OPTION_PRODUCT_VIPER 0x6600
#define OPTION_PRODUCT_VIPER_BUS 0x6601
#define OPTION_PRODUCT_GT_MAX_READY 0x6701
-#define OPTION_PRODUCT_GT_MAX 0x6711
#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721
#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741
#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761
-#define OPTION_PRODUCT_FUJI_NETWORK_LIGHT 0x6731
-#define OPTION_PRODUCT_FUJI_NETWORK_GT 0x6751
-#define OPTION_PRODUCT_FUJI_NETWORK_EX 0x6771
#define OPTION_PRODUCT_KOI_MODEM 0x6800
-#define OPTION_PRODUCT_KOI_NETWORK 0x6811
#define OPTION_PRODUCT_SCORPION_MODEM 0x6901
-#define OPTION_PRODUCT_SCORPION_NETWORK 0x6911
#define OPTION_PRODUCT_ETNA_MODEM 0x7001
-#define OPTION_PRODUCT_ETNA_NETWORK 0x7011
#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021
#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041
#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061
-#define OPTION_PRODUCT_ETNA_NETWORK_LITE 0x7031
-#define OPTION_PRODUCT_ETNA_NETWORK_GT 0x7051
-#define OPTION_PRODUCT_ETNA_NETWORK_EX 0x7071
#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100
-#define OPTION_PRODUCT_ETNA_KOI_NETWORK 0x7111
#define HUAWEI_VENDOR_ID 0x12D1
#define HUAWEI_PRODUCT_E600 0x1001
#define HUAWEI_PRODUCT_E220 0x1003
#define HUAWEI_PRODUCT_E220BIS 0x1004
#define HUAWEI_PRODUCT_E1401 0x1401
+#define HUAWEI_PRODUCT_E1402 0x1402
#define HUAWEI_PRODUCT_E1403 0x1403
+#define HUAWEI_PRODUCT_E1404 0x1404
#define HUAWEI_PRODUCT_E1405 0x1405
#define HUAWEI_PRODUCT_E1406 0x1406
+#define HUAWEI_PRODUCT_E1407 0x1407
#define HUAWEI_PRODUCT_E1408 0x1408
#define HUAWEI_PRODUCT_E1409 0x1409
+#define HUAWEI_PRODUCT_E140A 0x140A
+#define HUAWEI_PRODUCT_E140B 0x140B
+#define HUAWEI_PRODUCT_E140C 0x140C
+#define HUAWEI_PRODUCT_E140D 0x140D
+#define HUAWEI_PRODUCT_E140E 0x140E
+#define HUAWEI_PRODUCT_E140F 0x140F
#define HUAWEI_PRODUCT_E1410 0x1410
#define HUAWEI_PRODUCT_E1411 0x1411
#define HUAWEI_PRODUCT_E1412 0x1412
@@ -121,6 +119,44 @@ static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *po
#define HUAWEI_PRODUCT_E1417 0x1417
#define HUAWEI_PRODUCT_E1418 0x1418
#define HUAWEI_PRODUCT_E1419 0x1419
+#define HUAWEI_PRODUCT_E141A 0x141A
+#define HUAWEI_PRODUCT_E141B 0x141B
+#define HUAWEI_PRODUCT_E141C 0x141C
+#define HUAWEI_PRODUCT_E141D 0x141D
+#define HUAWEI_PRODUCT_E141E 0x141E
+#define HUAWEI_PRODUCT_E141F 0x141F
+#define HUAWEI_PRODUCT_E1420 0x1420
+#define HUAWEI_PRODUCT_E1421 0x1421
+#define HUAWEI_PRODUCT_E1422 0x1422
+#define HUAWEI_PRODUCT_E1423 0x1423
+#define HUAWEI_PRODUCT_E1424 0x1424
+#define HUAWEI_PRODUCT_E1425 0x1425
+#define HUAWEI_PRODUCT_E1426 0x1426
+#define HUAWEI_PRODUCT_E1427 0x1427
+#define HUAWEI_PRODUCT_E1428 0x1428
+#define HUAWEI_PRODUCT_E1429 0x1429
+#define HUAWEI_PRODUCT_E142A 0x142A
+#define HUAWEI_PRODUCT_E142B 0x142B
+#define HUAWEI_PRODUCT_E142C 0x142C
+#define HUAWEI_PRODUCT_E142D 0x142D
+#define HUAWEI_PRODUCT_E142E 0x142E
+#define HUAWEI_PRODUCT_E142F 0x142F
+#define HUAWEI_PRODUCT_E1430 0x1430
+#define HUAWEI_PRODUCT_E1431 0x1431
+#define HUAWEI_PRODUCT_E1432 0x1432
+#define HUAWEI_PRODUCT_E1433 0x1433
+#define HUAWEI_PRODUCT_E1434 0x1434
+#define HUAWEI_PRODUCT_E1435 0x1435
+#define HUAWEI_PRODUCT_E1436 0x1436
+#define HUAWEI_PRODUCT_E1437 0x1437
+#define HUAWEI_PRODUCT_E1438 0x1438
+#define HUAWEI_PRODUCT_E1439 0x1439
+#define HUAWEI_PRODUCT_E143A 0x143A
+#define HUAWEI_PRODUCT_E143B 0x143B
+#define HUAWEI_PRODUCT_E143C 0x143C
+#define HUAWEI_PRODUCT_E143D 0x143D
+#define HUAWEI_PRODUCT_E143E 0x143E
+#define HUAWEI_PRODUCT_E143F 0x143F
#define NOVATELWIRELESS_VENDOR_ID 0x1410
@@ -218,8 +254,19 @@ static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *po
/* ZTE PRODUCTS */
#define ZTE_VENDOR_ID 0x19d2
#define ZTE_PRODUCT_MF628 0x0015
+#define ZTE_PRODUCT_MF626 0x0031
#define ZTE_PRODUCT_CDMA_TECH 0xfffe
+/* Ericsson products */
+#define ERICSSON_VENDOR_ID 0x0bdb
+#define ERICSSON_PRODUCT_F3507G 0x1900
+
+/* Pantech products */
+#define PANTECH_VENDOR_ID 0x106c
+#define PANTECH_PRODUCT_PC5740 0x3701
+#define PANTECH_PRODUCT_PC5750 0x3702 /* PX-500 */
+#define PANTECH_PRODUCT_UM150 0x3711
+
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -235,36 +282,34 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_LIGHT) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_GT) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_EX) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_NETWORK) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_NETWORK) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_LITE) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_GT) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1402, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1404, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1407, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140A, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140B, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140C, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140D, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140E, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140F, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412, 0xff, 0xff, 0xff) },
@@ -275,6 +320,44 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141A, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141B, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141C, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141D, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141E, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141F, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1420, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1421, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1422, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1423, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1424, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1425, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1426, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1427, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1428, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1429, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142A, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142B, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142C, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142D, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142E, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142F, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1430, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1431, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1432, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1433, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1434, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1435, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1436, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1437, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1438, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1439, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143A, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143B, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143C, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_9508) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, /* Novatel Merlin V640/XV620 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, /* Novatel Merlin V620/S620 */
@@ -318,7 +401,8 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(DELL_VENDOR_ID, 0x8136) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8138) }, /* Dell Wireless 5520 Voda I Mobile Broadband (3G HSDPA) Minicard */
- { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8147) }, /* Dell Wireless 5530 Mobile Broadband (3G HSPA) Mini-Card */
+ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
{ USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) },
@@ -347,8 +431,13 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
+ { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
+ { USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G) },
+ { USB_DEVICE(PANTECH_VENDOR_ID, PANTECH_PRODUCT_PC5740) },
+ { USB_DEVICE(PANTECH_VENDOR_ID, PANTECH_PRODUCT_PC5750) },
+ { USB_DEVICE(PANTECH_VENDOR_ID, PANTECH_PRODUCT_UM150) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -427,7 +516,8 @@ static int __init option_init(void)
if (retval)
goto failed_driver_register;
- info(DRIVER_DESC ": " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 90843784716..491c8857b64 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -1147,7 +1147,7 @@ static int __init pl2303_init(void)
retval = usb_register(&pl2303_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&pl2303_device);
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 72903ac9f5c..4b463cd140e 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -250,17 +250,18 @@ static void safe_read_bulk_callback(struct urb *urb)
if (!fcs) {
int actual_length = data[length - 2] >> 2;
if (actual_length <= (length - 2)) {
- info("%s - actual: %d", __func__,
- actual_length);
+ dev_info(&urb->dev->dev, "%s - actual: %d\n",
+ __func__, actual_length);
tty_insert_flip_string(tty,
data, actual_length);
tty_flip_buffer_push(tty);
} else {
- err("%s - inconsistent lengths %d:%d",
+ dev_err(&port->dev,
+ "%s - inconsistent lengths %d:%d\n",
__func__, actual_length, length);
}
} else {
- err("%s - bad CRC %x", __func__, fcs);
+ dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
}
} else {
tty_insert_flip_string(tty, data, length);
@@ -277,8 +278,9 @@ static void safe_read_bulk_callback(struct urb *urb)
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __func__, result);
/* FIXME: Need a mechanism to retry later if this happens */
}
@@ -369,8 +371,9 @@ static int safe_write(struct tty_struct *tty, struct usb_serial_port *port,
result = usb_submit_urb(port->write_urb, GFP_KERNEL);
if (result) {
port->write_urb_busy = 0;
- err("%s - failed submitting write urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, result);
return 0;
}
dbg("%s urb: %p submitted", __func__, port->write_urb);
@@ -428,14 +431,13 @@ static int __init safe_init(void)
{
int i, retval;
- info(DRIVER_VERSION " " DRIVER_AUTHOR);
- info(DRIVER_DESC);
- info("vendor: %x product: %x safe: %d padded: %d\n",
- vendor, product, safe, padded);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
/* if we have vendor / product parameters patch them into id list */
if (vendor || product) {
- info("vendor: %x product: %x\n", vendor, product);
+ printk(KERN_INFO KBUILD_MODNAME ": vendor: %x product: %x\n",
+ vendor, product);
for (i = 0; i < ARRAY_SIZE(id_table); i++) {
if (!id_table[i].idVendor && !id_table[i].idProduct) {
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 8b9eaf38367..0f2b67244af 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -247,7 +247,7 @@ static int sierra_send_setup(struct tty_struct *tty,
struct sierra_port_private *portdata;
__u16 interface = 0;
- dbg("%s", __func__);
+ dev_dbg(&port->dev, "%s", __func__);
portdata = usb_get_serial_port_data(port);
@@ -284,7 +284,7 @@ static int sierra_send_setup(struct tty_struct *tty,
static void sierra_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
- dbg("%s", __func__);
+ dev_dbg(&port->dev, "%s", __func__);
tty_termios_copy_hw(tty->termios, old_termios);
sierra_send_setup(tty, port);
}
@@ -295,6 +295,7 @@ static int sierra_tiocmget(struct tty_struct *tty, struct file *file)
unsigned int value;
struct sierra_port_private *portdata;
+ dev_dbg(&port->dev, "%s", __func__);
portdata = usb_get_serial_port_data(port);
value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
@@ -334,14 +335,14 @@ static void sierra_outdat_callback(struct urb *urb)
int status = urb->status;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
+ dev_dbg(&port->dev, "%s - port %d", __func__, port->number);
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree(urb->transfer_buffer);
if (status)
- dbg("%s - nonzero write bulk status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero write bulk status "
+ "received: %d", __func__, status);
spin_lock_irqsave(&portdata->lock, flags);
--portdata->outstanding_urbs;
@@ -363,12 +364,12 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
portdata = usb_get_serial_port_data(port);
- dbg("%s: write (%d chars)", __func__, count);
+ dev_dbg(&port->dev, "%s: write (%d chars)", __func__, count);
spin_lock_irqsave(&portdata->lock, flags);
if (portdata->outstanding_urbs > N_OUT_URB) {
spin_unlock_irqrestore(&portdata->lock, flags);
- dbg("%s - write limit hit\n", __func__);
+ dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
return 0;
}
portdata->outstanding_urbs++;
@@ -437,8 +438,8 @@ static void sierra_indat_callback(struct urb *urb)
port = urb->context;
if (status) {
- dbg("%s: nonzero status: %d on endpoint %02x.",
- __func__, status, endpoint);
+ dev_dbg(&port->dev, "%s: nonzero status: %d on"
+ " endpoint %02x.", __func__, status, endpoint);
} else {
if (urb->actual_length) {
tty = tty_port_tty_get(&port->port);
@@ -447,7 +448,8 @@ static void sierra_indat_callback(struct urb *urb)
tty_flip_buffer_push(tty);
tty_kref_put(tty);
} else
- dbg("%s: empty read urb received", __func__);
+ dev_dbg(&port->dev, "%s: empty read urb"
+ " received", __func__);
/* Resubmit urb so we continue receiving */
if (port->port.count && status != -ESHUTDOWN) {
@@ -468,15 +470,17 @@ static void sierra_instat_callback(struct urb *urb)
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
- dbg("%s", __func__);
- dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
+ dev_dbg(&port->dev, "%s", __func__);
+ dev_dbg(&port->dev, "%s: urb %p port %p has data %p", __func__,
+ urb, port, portdata);
if (status == 0) {
struct usb_ctrlrequest *req_pkt =
(struct usb_ctrlrequest *)urb->transfer_buffer;
if (!req_pkt) {
- dbg("%s: NULL req_pkt\n", __func__);
+ dev_dbg(&port->dev, "%s: NULL req_pkt\n",
+ __func__);
return;
}
if ((req_pkt->bRequestType == 0xA1) &&
@@ -487,7 +491,8 @@ static void sierra_instat_callback(struct urb *urb)
sizeof(struct usb_ctrlrequest));
struct tty_struct *tty;
- dbg("%s: signal x%x", __func__, signals);
+ dev_dbg(&port->dev, "%s: signal x%x", __func__,
+ signals);
old_dcd_state = portdata->dcd_state;
portdata->cts_state = 1;
@@ -501,19 +506,20 @@ static void sierra_instat_callback(struct urb *urb)
tty_hangup(tty);
tty_kref_put(tty);
} else {
- dbg("%s: type %x req %x", __func__,
- req_pkt->bRequestType, req_pkt->bRequest);
+ dev_dbg(&port->dev, "%s: type %x req %x",
+ __func__, req_pkt->bRequestType,
+ req_pkt->bRequest);
}
} else
- dbg("%s: error %d", __func__, status);
+ dev_dbg(&port->dev, "%s: error %d", __func__, status);
/* Resubmit urb so we continue receiving IRQ data */
if (status != -ESHUTDOWN) {
urb->dev = serial->dev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
- dbg("%s: resubmit intr urb failed. (%d)",
- __func__, err);
+ dev_dbg(&port->dev, "%s: resubmit intr urb "
+ "failed. (%d)", __func__, err);
}
}
@@ -523,14 +529,14 @@ static int sierra_write_room(struct tty_struct *tty)
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
+ dev_dbg(&port->dev, "%s - port %d", __func__, port->number);
/* try to give a good number back based on if we have any free urbs at
* this point in time */
spin_lock_irqsave(&portdata->lock, flags);
if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) {
spin_unlock_irqrestore(&portdata->lock, flags);
- dbg("%s - write limit hit\n", __func__);
+ dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
return 0;
}
spin_unlock_irqrestore(&portdata->lock, flags);
@@ -549,7 +555,7 @@ static int sierra_open(struct tty_struct *tty,
portdata = usb_get_serial_port_data(port);
- dbg("%s", __func__);
+ dev_dbg(&port->dev, "%s", __func__);
/* Set some sane defaults */
portdata->rts_state = 1;
@@ -561,8 +567,8 @@ static int sierra_open(struct tty_struct *tty,
if (!urb)
continue;
if (urb->dev != serial->dev) {
- dbg("%s: dev %p != %p", __func__,
- urb->dev, serial->dev);
+ dev_dbg(&port->dev, "%s: dev %p != %p",
+ __func__, urb->dev, serial->dev);
continue;
}
@@ -601,7 +607,7 @@ static void sierra_close(struct tty_struct *tty,
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
- dbg("%s", __func__);
+ dev_dbg(&port->dev, "%s", __func__);
portdata = usb_get_serial_port_data(port);
portdata->rts_state = 0;
@@ -630,7 +636,7 @@ static int sierra_startup(struct usb_serial *serial)
int i;
int j;
- dbg("%s", __func__);
+ dev_dbg(&serial->dev->dev, "%s", __func__);
/* Set Device mode to D0 */
sierra_set_power_state(serial->dev, 0x0000);
@@ -644,8 +650,9 @@ static int sierra_startup(struct usb_serial *serial)
port = serial->port[i];
portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
if (!portdata) {
- dbg("%s: kmalloc for sierra_port_private (%d) failed!.",
- __func__, i);
+ dev_dbg(&port->dev, "%s: kmalloc for "
+ "sierra_port_private (%d) failed!.",
+ __func__, i);
return -ENOMEM;
}
spin_lock_init(&portdata->lock);
@@ -665,8 +672,8 @@ static int sierra_startup(struct usb_serial *serial)
for (j = 0; j < N_IN_URB; ++j) {
urb = usb_alloc_urb(0, GFP_KERNEL);
if (urb == NULL) {
- dbg("%s: alloc for in port failed.",
- __func__);
+ dev_dbg(&port->dev, "%s: alloc for in "
+ "port failed.", __func__);
continue;
}
/* Fill URB using supplied data. */
@@ -688,7 +695,7 @@ static void sierra_shutdown(struct usb_serial *serial)
struct usb_serial_port *port;
struct sierra_port_private *portdata;
- dbg("%s", __func__);
+ dev_dbg(&serial->dev->dev, "%s", __func__);
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
@@ -743,7 +750,8 @@ static int __init sierra_init(void)
if (retval)
goto failed_driver_register;
- info(DRIVER_DESC ": " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 1533d6e1223..a65bc2bd8e7 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -589,8 +589,8 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
case 1000000:
buf[0] = 0x0b; break;
default:
- err("spcp825 driver does not support the baudrate "
- "requested, using default of 9600.");
+ dev_err(&port->dev, "spcp825 driver does not support the "
+ "baudrate requested, using default of 9600.\n");
}
/* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
@@ -629,7 +629,8 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
SET_UART_FORMAT_TYPE, SET_UART_FORMAT,
uartdata, 0, NULL, 0, 100);
if (i < 0)
- err("Set UART format %#x failed (error = %d)", uartdata, i);
+ dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n",
+ uartdata, i);
dbg("0x21:0x40:0:0 %d\n", i);
if (cflag & CRTSCTS) {
@@ -1054,7 +1055,8 @@ static int __init spcp8x5_init(void)
retval = usb_register(&spcp8x5_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&spcp8x5_device);
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index c90237d48b0..31c42d1cae1 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -85,7 +85,6 @@
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
-#include <linux/firmware.h>
#include "ti_usb_3410_5052.h"
@@ -383,7 +382,8 @@ static int __init ti_init(void)
if (ret)
goto failed_usb;
- info(TI_DRIVER_DESC " " TI_DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":"
+ TI_DRIVER_DESC "\n");
return 0;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index e7d4246027b..8be3f39891c 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1121,7 +1121,8 @@ static int __init usb_serial_init(void)
result = bus_register(&usb_serial_bus_type);
if (result) {
- err("%s - registering bus driver failed", __func__);
+ printk(KERN_ERR "usb-serial: %s - registering bus driver "
+ "failed\n", __func__);
goto exit_bus;
}
@@ -1142,25 +1143,28 @@ static int __init usb_serial_init(void)
tty_set_operations(usb_serial_tty_driver, &serial_ops);
result = tty_register_driver(usb_serial_tty_driver);
if (result) {
- err("%s - tty_register_driver failed", __func__);
+ printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",
+ __func__);
goto exit_reg_driver;
}
/* register the USB driver */
result = usb_register(&usb_serial_driver);
if (result < 0) {
- err("%s - usb_register failed", __func__);
+ printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
+ __func__);
goto exit_tty;
}
/* register the generic driver, if we should */
result = usb_serial_generic_register(debug);
if (result < 0) {
- err("%s - registering generic driver failed", __func__);
+ printk(KERN_ERR "usb-serial: %s - registering generic "
+ "driver failed\n", __func__);
goto exit_generic;
}
- info(DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return result;
@@ -1174,7 +1178,8 @@ exit_reg_driver:
bus_unregister(&usb_serial_bus_type);
exit_bus:
- err("%s - returning with error %d", __func__, result);
+ printk(KERN_ERR "usb-serial: %s - returning with error %d\n",
+ __func__, result);
put_tty_driver(usb_serial_tty_driver);
return result;
}
@@ -1233,11 +1238,11 @@ int usb_serial_register(struct usb_serial_driver *driver)
retval = usb_serial_bus_register(driver);
if (retval) {
- err("problem %d when registering driver %s",
- retval, driver->description);
+ printk(KERN_ERR "usb-serial: problem %d when registering "
+ "driver %s\n", retval, driver->description);
list_del(&driver->driver_list);
} else
- info("USB Serial support registered for %s",
+ printk(KERN_INFO "USB Serial support registered for %s\n",
driver->description);
return retval;
@@ -1248,7 +1253,8 @@ EXPORT_SYMBOL_GPL(usb_serial_register);
void usb_serial_deregister(struct usb_serial_driver *device)
{
/* must be called with BKL held */
- info("USB Serial deregistering driver %s", device->description);
+ printk(KERN_INFO "USB Serial deregistering driver %s\n",
+ device->description);
list_del(&device->driver_list);
usb_serial_bus_deregister(device);
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index a6d1c75a1c8..4facce3d936 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -768,7 +768,7 @@ static int visor_probe(struct usb_serial *serial,
dbg("%s", __func__);
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
- err("active config #%d != 1 ??",
+ dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
serial->dev->actconfig->desc.bConfigurationValue);
return -ENODEV;
}
@@ -971,11 +971,14 @@ static int __init visor_init(void)
break;
}
}
- info(
- "Untested USB device specified at time of module insertion");
- info("Warning: This is not guaranteed to work");
- info("Using a newer kernel is preferred to this method");
- info("Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x",
+ printk(KERN_INFO KBUILD_MODNAME
+ ": Untested USB device specified at time of module insertion\n");
+ printk(KERN_INFO KBUILD_MODNAME
+ ": Warning: This is not guaranteed to work\n");
+ printk(KERN_INFO KBUILD_MODNAME
+ ": Using a newer kernel is preferred to this method\n");
+ printk(KERN_INFO KBUILD_MODNAME
+ ": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n",
vendor, product);
}
retval = usb_serial_register(&handspring_device);
@@ -990,7 +993,7 @@ static int __init visor_init(void)
retval = usb_register(&visor_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return 0;
failed_usb_register:
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 11c8b97a517..5335d3211c0 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -303,12 +303,15 @@ static int whiteheat_firmware_download(struct usb_serial *serial,
if (request_ihex_firmware(&firmware_fw, "whiteheat.fw",
&serial->dev->dev)) {
- err("%s - request \"whiteheat.fw\" failed", __func__);
+ dev_err(&serial->dev->dev,
+ "%s - request \"whiteheat.fw\" failed\n", __func__);
goto out;
}
if (request_ihex_firmware(&loader_fw, "whiteheat_loader.fw",
&serial->dev->dev)) {
- err("%s - request \"whiteheat_loader.fw\" failed", __func__);
+ dev_err(&serial->dev->dev,
+ "%s - request \"whiteheat_loader.fw\" failed\n",
+ __func__);
goto out;
}
ret = 0;
@@ -320,9 +323,10 @@ static int whiteheat_firmware_download(struct usb_serial *serial,
(unsigned char *)record->data,
be16_to_cpu(record->len), 0xa0);
if (response < 0) {
- err("%s - ezusb_writememory failed for loader (%d %04X %p %d)",
- __func__, response, be32_to_cpu(record->addr),
- record->data, be16_to_cpu(record->len));
+ dev_err(&serial->dev->dev, "%s - ezusb_writememory "
+ "failed for loader (%d %04X %p %d)\n",
+ __func__, response, be32_to_cpu(record->addr),
+ record->data, be16_to_cpu(record->len));
break;
}
record = ihex_next_binrec(record);
@@ -338,9 +342,11 @@ static int whiteheat_firmware_download(struct usb_serial *serial,
(unsigned char *)record->data,
be16_to_cpu(record->len), 0xa3);
if (response < 0) {
- err("%s - ezusb_writememory failed for first firmware step (%d %04X %p %d)",
- __func__, response, be32_to_cpu(record->addr),
- record->data, be16_to_cpu(record->len));
+ dev_err(&serial->dev->dev, "%s - ezusb_writememory "
+ "failed for first firmware step "
+ "(%d %04X %p %d)\n", __func__, response,
+ be32_to_cpu(record->addr), record->data,
+ be16_to_cpu(record->len));
break;
}
++record;
@@ -354,9 +360,11 @@ static int whiteheat_firmware_download(struct usb_serial *serial,
(unsigned char *)record->data,
be16_to_cpu(record->len), 0xa0);
if (response < 0) {
- err("%s - ezusb_writememory failed for second firmware step (%d %04X %p %d)",
- __func__, response, be32_to_cpu(record->addr),
- record->data, be16_to_cpu(record->len));
+ dev_err(&serial->dev->dev, "%s - ezusb_writememory "
+ "failed for second firmware step "
+ "(%d %04X %p %d)\n", __func__, response,
+ be32_to_cpu(record->addr), record->data,
+ be16_to_cpu(record->len));
break;
}
++record;
@@ -421,12 +429,12 @@ static int whiteheat_attach(struct usb_serial *serial)
ret = usb_bulk_msg(serial->dev, pipe, command, 2,
&alen, COMMAND_TIMEOUT_MS);
if (ret) {
- err("%s: Couldn't send command [%d]",
- serial->type->description, ret);
+ dev_err(&serial->dev->dev, "%s: Couldn't send command [%d]\n",
+ serial->type->description, ret);
goto no_firmware;
} else if (alen != 2) {
- err("%s: Send command incomplete [%d]",
- serial->type->description, alen);
+ dev_err(&serial->dev->dev, "%s: Send command incomplete [%d]\n",
+ serial->type->description, alen);
goto no_firmware;
}
@@ -437,31 +445,33 @@ static int whiteheat_attach(struct usb_serial *serial)
ret = usb_bulk_msg(serial->dev, pipe, result,
sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS);
if (ret) {
- err("%s: Couldn't get results [%d]",
- serial->type->description, ret);
+ dev_err(&serial->dev->dev, "%s: Couldn't get results [%d]\n",
+ serial->type->description, ret);
goto no_firmware;
} else if (alen != sizeof(*hw_info) + 1) {
- err("%s: Get results incomplete [%d]",
- serial->type->description, alen);
+ dev_err(&serial->dev->dev, "%s: Get results incomplete [%d]\n",
+ serial->type->description, alen);
goto no_firmware;
} else if (result[0] != command[0]) {
- err("%s: Command failed [%d]",
- serial->type->description, result[0]);
+ dev_err(&serial->dev->dev, "%s: Command failed [%d]\n",
+ serial->type->description, result[0]);
goto no_firmware;
}
hw_info = (struct whiteheat_hw_info *)&result[1];
- info("%s: Driver %s: Firmware v%d.%02d", serial->type->description,
- DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev);
+ dev_info(&serial->dev->dev, "%s: Driver %s: Firmware v%d.%02d\n",
+ serial->type->description, DRIVER_VERSION,
+ hw_info->sw_major_rev, hw_info->sw_minor_rev);
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
info = kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL);
if (info == NULL) {
- err("%s: Out of memory for port structures\n",
- serial->type->description);
+ dev_err(&port->dev,
+ "%s: Out of memory for port structures\n",
+ serial->type->description);
goto no_private;
}
@@ -481,18 +491,20 @@ static int whiteheat_attach(struct usb_serial *serial)
for (j = 0; j < urb_pool_size; j++) {
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- err("No free urbs available");
+ dev_err(&port->dev, "No free urbs available\n");
goto no_rx_urb;
}
buf_size = port->read_urb->transfer_buffer_length;
urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);
if (!urb->transfer_buffer) {
- err("Couldn't allocate urb buffer");
+ dev_err(&port->dev,
+ "Couldn't allocate urb buffer\n");
goto no_rx_buf;
}
wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
if (!wrap) {
- err("Couldn't allocate urb wrapper");
+ dev_err(&port->dev,
+ "Couldn't allocate urb wrapper\n");
goto no_rx_wrap;
}
usb_fill_bulk_urb(urb, serial->dev,
@@ -505,18 +517,20 @@ static int whiteheat_attach(struct usb_serial *serial)
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- err("No free urbs available");
+ dev_err(&port->dev, "No free urbs available\n");
goto no_tx_urb;
}
buf_size = port->write_urb->transfer_buffer_length;
urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);
if (!urb->transfer_buffer) {
- err("Couldn't allocate urb buffer");
+ dev_err(&port->dev,
+ "Couldn't allocate urb buffer\n");
goto no_tx_buf;
}
wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
if (!wrap) {
- err("Couldn't allocate urb wrapper");
+ dev_err(&port->dev,
+ "Couldn't allocate urb wrapper\n");
goto no_tx_wrap;
}
usb_fill_bulk_urb(urb, serial->dev,
@@ -534,8 +548,9 @@ static int whiteheat_attach(struct usb_serial *serial)
command_info = kmalloc(sizeof(struct whiteheat_command_private),
GFP_KERNEL);
if (command_info == NULL) {
- err("%s: Out of memory for port structures\n",
- serial->type->description);
+ dev_err(&serial->dev->dev,
+ "%s: Out of memory for port structures\n",
+ serial->type->description);
goto no_command_private;
}
@@ -552,12 +567,15 @@ static int whiteheat_attach(struct usb_serial *serial)
no_firmware:
/* Firmware likely not running */
- err("%s: Unable to retrieve firmware version, try replugging\n",
- serial->type->description);
- err("%s: If the firmware is not running (status led not blinking)\n",
- serial->type->description);
- err("%s: please contact support@connecttech.com\n",
- serial->type->description);
+ dev_err(&serial->dev->dev,
+ "%s: Unable to retrieve firmware version, try replugging\n",
+ serial->type->description);
+ dev_err(&serial->dev->dev,
+ "%s: If the firmware is not running (status led not blinking)\n",
+ serial->type->description);
+ dev_err(&serial->dev->dev,
+ "%s: please contact support@connecttech.com\n",
+ serial->type->description);
kfree(result);
return -ENODEV;
@@ -680,8 +698,9 @@ static int whiteheat_open(struct tty_struct *tty,
/* Start reading from the device */
retval = start_port_read(port);
if (retval) {
- err("%s - failed submitting read urb, error %d",
- __func__, retval);
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __func__, retval);
firm_close(port);
stop_command_port(port->serial);
goto exit;
@@ -806,8 +825,9 @@ static int whiteheat_write(struct tty_struct *tty,
urb->transfer_buffer_length = bytes;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, result);
sent = result;
spin_lock_irqsave(&info->lock, flags);
list_add(tmp, &info->tx_urbs_free);
@@ -1075,7 +1095,7 @@ static void whiteheat_read_callback(struct urb *urb)
wrap = urb_to_wrap(urb, &info->rx_urbs_submitted);
if (!wrap) {
spin_unlock(&info->lock);
- err("%s - Not my urb!", __func__);
+ dev_err(&port->dev, "%s - Not my urb!\n", __func__);
return;
}
list_del(&wrap->list);
@@ -1119,7 +1139,7 @@ static void whiteheat_write_callback(struct urb *urb)
wrap = urb_to_wrap(urb, &info->tx_urbs_submitted);
if (!wrap) {
spin_unlock(&info->lock);
- err("%s - Not my urb!", __func__);
+ dev_err(&port->dev, "%s - Not my urb!\n", __func__);
return;
}
list_move(&wrap->list, &info->tx_urbs_free);
@@ -1383,8 +1403,9 @@ static int start_command_port(struct usb_serial *serial)
command_port->read_urb->dev = serial->dev;
retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL);
if (retval) {
- err("%s - failed submitting read urb, error %d",
- __func__, retval);
+ dev_err(&serial->dev->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __func__, retval);
goto exit;
}
}
@@ -1522,7 +1543,8 @@ static void rx_data_softint(struct work_struct *work)
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) {
- err("%s - failed resubmitting read urb, error %d",
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
__func__, result);
spin_lock_irqsave(&info->lock, flags);
list_add(tmp, &info->rx_urbs_free);
@@ -1556,7 +1578,8 @@ static int __init whiteheat_init(void)
retval = usb_register(&whiteheat_driver);
if (retval)
goto failed_usb_register;
- info(DRIVER_DESC " " DRIVER_VERSION);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
failed_usb_register:
usb_serial_deregister(&whiteheat_device);
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 4995bb595ae..2dd9bd4bff5 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -95,11 +95,10 @@ int usb_stor_huawei_e220_init(struct us_data *us)
{
int result;
- us->iobuf[0] = 0x1;
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
USB_REQ_SET_FEATURE,
USB_TYPE_STANDARD | USB_RECIP_DEVICE,
- 0x01, 0x0, us->iobuf, 0x1, 1000);
+ 0x01, 0x0, NULL, 0x0, 1000);
US_DEBUGP("usb_control_msg performing result is %d\n", result);
return (result ? 0 : -1);
}
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index 98b89ea9e31..c7bf8954b4e 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -78,8 +78,8 @@ static void usb_onetouch_irq(struct urb *urb)
resubmit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
- err ("can't resubmit intr, %s-%s/input0, retval %d",
- onetouch->udev->bus->bus_name,
+ dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, "
+ "retval %d\n", onetouch->udev->bus->bus_name,
onetouch->udev->devpath, retval);
}
@@ -90,7 +90,7 @@ static int usb_onetouch_open(struct input_dev *dev)
onetouch->is_open = 1;
onetouch->irq->dev = onetouch->udev;
if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
- err("usb_submit_urb failed");
+ dev_err(&dev->dev, "usb_submit_urb failed\n");
return -EIO;
}
@@ -117,7 +117,8 @@ static void usb_onetouch_pm_hook(struct us_data *us, int action)
break;
case US_RESUME:
if (usb_submit_urb(onetouch->irq, GFP_KERNEL) != 0)
- err("usb_submit_urb failed");
+ dev_err(&onetouch->irq->dev->dev,
+ "usb_submit_urb failed\n");
break;
default:
break;
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 3523a0bfa0f..79108d5d317 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -663,7 +663,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
}
/* Did we transfer less than the minimum amount required? */
- if (srb->result == SAM_STAT_GOOD &&
+ if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) &&
scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index cd155475cb6..a2b9ebbef38 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1628,97 +1628,332 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100,
/* Reported by fangxiaozhi <huananhu@huawei.com>
* This brings the HUAWEI data card devices into multi-port mode
*/
-UNUSUAL_DEV( 0x12d1, 0x1001, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1001, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1004, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1004, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1401, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1401, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1403, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1402, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1405, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1403, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1406, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1404, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1408, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1405, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1409, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1406, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1410, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1407, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1411, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1408, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1412, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1409, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1413, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x140A, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1414, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x140B, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1415, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x140C, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1416, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x140D, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1417, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x140E, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1418, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x140F, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
0),
-UNUSUAL_DEV( 0x12d1, 0x1419, 0x0000, 0x0000,
+UNUSUAL_DEV( 0x12d1, 0x1410, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1411, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1412, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1413, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1414, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1415, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1416, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1417, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1418, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1419, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141A, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141B, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141C, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141D, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141E, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141F, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1420, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1421, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1422, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1423, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1424, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1425, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1426, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1427, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1428, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1429, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142A, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142B, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142C, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142D, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142E, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142F, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1430, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1431, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1432, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1433, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1434, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1435, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1436, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1437, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1438, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1439, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143A, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143B, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143C, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143D, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143E, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143F, 0x0000, 0x0000,
"HUAWEI MOBILE",
"Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
@@ -1745,6 +1980,15 @@ UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Alexandre Oliva <oliva@lsd.ic.unicamp.br>
+ * 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 ),
+
/* Reported by Robert Schedel <r.schedel@yahoo.de>
* Note: this is a 'super top' device like the above 14cd/6600 device */
UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201,
@@ -1818,6 +2062,15 @@ UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Frederic Marchal <frederic.marchal@wowcompany.com>
+ * Mio Moov 330
+ */
+UNUSUAL_DEV( 0x3340, 0xffff, 0x0000, 0x0000,
+ "Mitac",
+ "Mio DigiWalker USB Sync",
+ US_SC_DEVICE,US_PR_DEVICE,NULL,
+ US_FL_MAX_SECTORS_64 ),
+
/* Reported by Andrey Rahmatullin <wrar@altlinux.org> */
UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100,
"iRiver",
diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig
new file mode 100644
index 00000000000..eb09a0a14a8
--- /dev/null
+++ b/drivers/usb/wusbcore/Kconfig
@@ -0,0 +1,41 @@
+#
+# Wireless USB Core configuration
+#
+config USB_WUSB
+ tristate "Enable Wireless USB extensions (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on USB
+ select UWB
+ select CRYPTO
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_CBC
+ select CRYPTO_MANAGER
+ select CRYPTO_AES
+ help
+ Enable the host-side support for Wireless USB.
+
+ To compile this support select Y (built in). It is safe to
+ select even if you don't have the hardware.
+
+config USB_WUSB_CBAF
+ tristate "Support WUSB Cable Based Association (CBA)"
+ depends on USB
+ help
+ Some WUSB devices support Cable Based Association. It's used to
+ enable the secure communication between the host and the
+ device.
+
+ Enable this option if your WUSB device must to be connected
+ via wired USB before establishing a wireless link.
+
+ It is safe to select even if you don't have a compatible
+ hardware.
+
+config USB_WUSB_CBAF_DEBUG
+ bool "Enable CBA debug messages"
+ depends on USB_WUSB_CBAF
+ help
+ Say Y here if you want the CBA to produce a bunch of debug messages
+ to the system log. Select this if you are having a problem with
+ CBA support and want to see more of what is going on.
+
diff --git a/drivers/usb/wusbcore/Makefile b/drivers/usb/wusbcore/Makefile
new file mode 100644
index 00000000000..75f1ade6625
--- /dev/null
+++ b/drivers/usb/wusbcore/Makefile
@@ -0,0 +1,26 @@
+obj-$(CONFIG_USB_WUSB) += wusbcore.o
+obj-$(CONFIG_USB_HWA_HCD) += wusb-wa.o
+obj-$(CONFIG_USB_WUSB_CBAF) += wusb-cbaf.o
+
+
+wusbcore-objs := \
+ crypto.o \
+ devconnect.o \
+ dev-sysfs.o \
+ mmc.o \
+ pal.o \
+ rh.o \
+ reservation.o \
+ security.o \
+ wusbhc.o
+
+wusb-cbaf-objs := cbaf.o
+
+wusb-wa-objs := wa-hc.o \
+ wa-nep.o \
+ wa-rpipe.o \
+ wa-xfer.o
+
+ifeq ($(CONFIG_USB_WUSB_CBAF_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c
new file mode 100644
index 00000000000..ab4788d1785
--- /dev/null
+++ b/drivers/usb/wusbcore/cbaf.c
@@ -0,0 +1,673 @@
+/*
+ * Wireless USB - Cable Based Association
+ *
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * 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.
+ *
+ *
+ * WUSB devices have to be paired (associated in WUSB lingo) so
+ * that they can connect to the system.
+ *
+ * One way of pairing is using CBA-Cable Based Association. First
+ * time you plug the device with a cable, association is done between
+ * host and device and subsequent times, you can connect wirelessly
+ * without having to associate again. That's the idea.
+ *
+ * This driver does nothing Earth shattering. It just provides an
+ * interface to chat with the wire-connected device so we can get a
+ * CDID (device ID) that might have been previously associated to a
+ * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet
+ * (connection context), with the CK being the secret, or connection
+ * key. This is the pairing data.
+ *
+ * When a device with the CBA capability connects, the probe routine
+ * just creates a bunch of sysfs files that a user space enumeration
+ * manager uses to allow it to connect wirelessly to the system or not.
+ *
+ * The process goes like this:
+ *
+ * 1. Device plugs, cbaf is loaded, notifications happen.
+ *
+ * 2. The connection manager (CM) sees a device with CBAF capability
+ * (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE).
+ *
+ * 3. The CM writes the host name, supported band groups, and the CHID
+ * (host ID) into the wusb_host_name, wusb_host_band_groups and
+ * wusb_chid files. These get sent to the device and the CDID (if
+ * any) for this host is requested.
+ *
+ * 4. The CM can verify that the device's supported band groups
+ * (wusb_device_band_groups) are compatible with the host.
+ *
+ * 5. The CM reads the wusb_cdid file.
+ *
+ * 6. The CM looks up its database
+ *
+ * 6.1 If it has a matching CHID,CDID entry, the device has been
+ * authorized before (paired) and nothing further needs to be
+ * done.
+ *
+ * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in
+ * its database), the device is assumed to be not known. The CM
+ * may associate the host with device by: writing a randomly
+ * generated CDID to wusb_cdid and then a random CK to wusb_ck
+ * (this uploads the new CC to the device).
+ *
+ * CMD may choose to prompt the user before associating with a new
+ * device.
+ *
+ * 7. Device is unplugged.
+ *
+ * When the device tries to connect wirelessly, it will present its
+ * CDID to the WUSB host controller. The CM will query the
+ * database. If the CHID/CDID pair found, it will (with a 4-way
+ * handshake) challenge the device to demonstrate it has the CK secret
+ * key (from our database) without actually exchanging it. Once
+ * satisfied, crypto keys are derived from the CK, the device is
+ * connected and all communication is encrypted.
+ *
+ * References:
+ * [WUSB-AM] Association Models Supplement to the Certified Wireless
+ * Universal Serial Bus Specification, version 1.0.
+ */
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/mutex.h>
+#include <linux/uwb.h>
+#include <linux/usb/wusb.h>
+#include <linux/usb/association.h>
+
+#define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */
+
+/* An instance of a Cable-Based-Association-Framework device */
+struct cbaf {
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+ void *buffer;
+ size_t buffer_size;
+
+ struct wusb_ckhdid chid;
+ char host_name[CBA_NAME_LEN];
+ u16 host_band_groups;
+
+ struct wusb_ckhdid cdid;
+ char device_name[CBA_NAME_LEN];
+ u16 device_band_groups;
+
+ struct wusb_ckhdid ck;
+};
+
+/*
+ * Verify that a CBAF USB-interface has what we need
+ *
+ * According to [WUSB-AM], CBA devices should provide at least two
+ * interfaces:
+ * - RETRIEVE_HOST_INFO
+ * - ASSOCIATE
+ *
+ * If the device doesn't provide these interfaces, we do not know how
+ * to deal with it.
+ */
+static int cbaf_check(struct cbaf *cbaf)
+{
+ int result;
+ struct device *dev = &cbaf->usb_iface->dev;
+ struct wusb_cbaf_assoc_info *assoc_info;
+ struct wusb_cbaf_assoc_request *assoc_request;
+ size_t assoc_size;
+ void *itr, *top;
+ int ar_rhi = 0, ar_assoc = 0;
+
+ result = usb_control_msg(
+ cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
+ CBAF_REQ_GET_ASSOCIATION_INFORMATION,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ cbaf->buffer, cbaf->buffer_size, 1000 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "Cannot get available association types: %d\n",
+ result);
+ return result;
+ }
+
+ assoc_info = cbaf->buffer;
+ if (result < sizeof(*assoc_info)) {
+ dev_err(dev, "Not enough data to decode association info "
+ "header (%zu vs %zu bytes required)\n",
+ (size_t)result, sizeof(*assoc_info));
+ return result;
+ }
+
+ assoc_size = le16_to_cpu(assoc_info->Length);
+ if (result < assoc_size) {
+ dev_err(dev, "Not enough data to decode association info "
+ "(%zu vs %zu bytes required)\n",
+ (size_t)assoc_size, sizeof(*assoc_info));
+ return result;
+ }
+ /*
+ * From now on, we just verify, but won't error out unless we
+ * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE}
+ * types.
+ */
+ itr = cbaf->buffer + sizeof(*assoc_info);
+ top = cbaf->buffer + assoc_size;
+ dev_dbg(dev, "Found %u association requests (%zu bytes)\n",
+ assoc_info->NumAssociationRequests, assoc_size);
+
+ while (itr < top) {
+ u16 ar_type, ar_subtype;
+ u32 ar_size;
+ const char *ar_name;
+
+ assoc_request = itr;
+
+ if (top - itr < sizeof(*assoc_request)) {
+ dev_err(dev, "Not enough data to decode associaton "
+ "request (%zu vs %zu bytes needed)\n",
+ top - itr, sizeof(*assoc_request));
+ break;
+ }
+
+ ar_type = le16_to_cpu(assoc_request->AssociationTypeId);
+ ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId);
+ ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize);
+ ar_name = "unknown";
+
+ switch (ar_type) {
+ case AR_TYPE_WUSB:
+ /* Verify we have what is mandated by [WUSB-AM]. */
+ switch (ar_subtype) {
+ case AR_TYPE_WUSB_RETRIEVE_HOST_INFO:
+ ar_name = "RETRIEVE_HOST_INFO";
+ ar_rhi = 1;
+ break;
+ case AR_TYPE_WUSB_ASSOCIATE:
+ /* send assoc data */
+ ar_name = "ASSOCIATE";
+ ar_assoc = 1;
+ break;
+ };
+ break;
+ };
+
+ dev_dbg(dev, "Association request #%02u: 0x%04x/%04x "
+ "(%zu bytes): %s\n",
+ assoc_request->AssociationDataIndex, ar_type,
+ ar_subtype, (size_t)ar_size, ar_name);
+
+ itr += sizeof(*assoc_request);
+ }
+
+ if (!ar_rhi) {
+ dev_err(dev, "Missing RETRIEVE_HOST_INFO association "
+ "request\n");
+ return -EINVAL;
+ }
+ if (!ar_assoc) {
+ dev_err(dev, "Missing ASSOCIATE association request\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct wusb_cbaf_host_info cbaf_host_info_defaults = {
+ .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId,
+ .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB),
+ .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
+ .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO),
+ .CHID_hdr = WUSB_AR_CHID,
+ .LangID_hdr = WUSB_AR_LangID,
+ .HostFriendlyName_hdr = WUSB_AR_HostFriendlyName,
+};
+
+/* Send WUSB host information (CHID and name) to a CBAF device */
+static int cbaf_send_host_info(struct cbaf *cbaf)
+{
+ struct wusb_cbaf_host_info *hi;
+ size_t name_len;
+ size_t hi_size;
+
+ hi = cbaf->buffer;
+ memset(hi, 0, sizeof(*hi));
+ *hi = cbaf_host_info_defaults;
+ hi->CHID = cbaf->chid;
+ hi->LangID = 0; /* FIXME: I guess... */
+ strlcpy(hi->HostFriendlyName, cbaf->host_name, CBA_NAME_LEN);
+ name_len = strlen(cbaf->host_name);
+ hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len);
+ hi_size = sizeof(*hi) + name_len;
+
+ return usb_control_msg(cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0),
+ CBAF_REQ_SET_ASSOCIATION_RESPONSE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x0101,
+ cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ hi, hi_size, 1000 /* FIXME: arbitrary */);
+}
+
+/*
+ * Get device's information (CDID) associated to CHID
+ *
+ * The device will return it's information (CDID, name, bandgroups)
+ * associated to the CHID we have set before, or 0 CDID and default
+ * name and bandgroup if no CHID set or unknown.
+ */
+static int cbaf_cdid_get(struct cbaf *cbaf)
+{
+ int result;
+ struct device *dev = &cbaf->usb_iface->dev;
+ struct wusb_cbaf_device_info *di;
+ size_t needed;
+
+ di = cbaf->buffer;
+ result = usb_control_msg(
+ cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
+ CBAF_REQ_GET_ASSOCIATION_REQUEST,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ di, cbaf->buffer_size, 1000 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "Cannot request device information: %d\n", result);
+ return result;
+ }
+
+ needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length);
+ if (result < needed) {
+ dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs "
+ "%zu bytes needed)\n", (size_t)result, needed);
+ return result;
+ }
+
+ strlcpy(cbaf->device_name, di->DeviceFriendlyName, CBA_NAME_LEN);
+ cbaf->cdid = di->CDID;
+ cbaf->device_band_groups = le16_to_cpu(di->BandGroups);
+
+ return 0;
+}
+
+static ssize_t cbaf_wusb_chid_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+ char pr_chid[WUSB_CKHDID_STRSIZE];
+
+ ckhdid_printf(pr_chid, sizeof(pr_chid), &cbaf->chid);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", pr_chid);
+}
+
+static ssize_t cbaf_wusb_chid_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx",
+ &cbaf->chid.data[0] , &cbaf->chid.data[1],
+ &cbaf->chid.data[2] , &cbaf->chid.data[3],
+ &cbaf->chid.data[4] , &cbaf->chid.data[5],
+ &cbaf->chid.data[6] , &cbaf->chid.data[7],
+ &cbaf->chid.data[8] , &cbaf->chid.data[9],
+ &cbaf->chid.data[10], &cbaf->chid.data[11],
+ &cbaf->chid.data[12], &cbaf->chid.data[13],
+ &cbaf->chid.data[14], &cbaf->chid.data[15]);
+
+ if (result != 16)
+ return -EINVAL;
+
+ result = cbaf_send_host_info(cbaf);
+ if (result < 0)
+ return result;
+ result = cbaf_cdid_get(cbaf);
+ if (result < 0)
+ return -result;
+ return size;
+}
+static DEVICE_ATTR(wusb_chid, 0600, cbaf_wusb_chid_show, cbaf_wusb_chid_store);
+
+static ssize_t cbaf_wusb_host_name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->host_name);
+}
+
+static ssize_t cbaf_wusb_host_name_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ result = sscanf(buf, "%63s", cbaf->host_name);
+ if (result != 1)
+ return -EINVAL;
+
+ return size;
+}
+static DEVICE_ATTR(wusb_host_name, 0600, cbaf_wusb_host_name_show,
+ cbaf_wusb_host_name_store);
+
+static ssize_t cbaf_wusb_host_band_groups_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->host_band_groups);
+}
+
+static ssize_t cbaf_wusb_host_band_groups_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+ u16 band_groups = 0;
+
+ result = sscanf(buf, "%04hx", &band_groups);
+ if (result != 1)
+ return -EINVAL;
+
+ cbaf->host_band_groups = band_groups;
+
+ return size;
+}
+
+static DEVICE_ATTR(wusb_host_band_groups, 0600,
+ cbaf_wusb_host_band_groups_show,
+ cbaf_wusb_host_band_groups_store);
+
+static const struct wusb_cbaf_device_info cbaf_device_info_defaults = {
+ .Length_hdr = WUSB_AR_Length,
+ .CDID_hdr = WUSB_AR_CDID,
+ .BandGroups_hdr = WUSB_AR_BandGroups,
+ .LangID_hdr = WUSB_AR_LangID,
+ .DeviceFriendlyName_hdr = WUSB_AR_DeviceFriendlyName,
+};
+
+static ssize_t cbaf_wusb_cdid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+ char pr_cdid[WUSB_CKHDID_STRSIZE];
+
+ ckhdid_printf(pr_cdid, sizeof(pr_cdid), &cbaf->cdid);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", pr_cdid);
+}
+
+static ssize_t cbaf_wusb_cdid_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+ struct wusb_ckhdid cdid;
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx",
+ &cdid.data[0] , &cdid.data[1],
+ &cdid.data[2] , &cdid.data[3],
+ &cdid.data[4] , &cdid.data[5],
+ &cdid.data[6] , &cdid.data[7],
+ &cdid.data[8] , &cdid.data[9],
+ &cdid.data[10], &cdid.data[11],
+ &cdid.data[12], &cdid.data[13],
+ &cdid.data[14], &cdid.data[15]);
+ if (result != 16)
+ return -EINVAL;
+
+ cbaf->cdid = cdid;
+
+ return size;
+}
+static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, cbaf_wusb_cdid_store);
+
+static ssize_t cbaf_wusb_device_band_groups_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->device_band_groups);
+}
+
+static DEVICE_ATTR(wusb_device_band_groups, 0600,
+ cbaf_wusb_device_band_groups_show,
+ NULL);
+
+static ssize_t cbaf_wusb_device_name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->device_name);
+}
+static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL);
+
+static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = {
+ .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId,
+ .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB),
+ .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
+ .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE),
+ .Length_hdr = WUSB_AR_Length,
+ .Length = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)),
+ .ConnectionContext_hdr = WUSB_AR_ConnectionContext,
+ .BandGroups_hdr = WUSB_AR_BandGroups,
+};
+
+static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = {
+ .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId,
+ .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
+ .Length_hdr = WUSB_AR_Length,
+ .AssociationStatus_hdr = WUSB_AR_AssociationStatus,
+};
+
+/*
+ * Send a new CC to the device.
+ */
+static int cbaf_cc_upload(struct cbaf *cbaf)
+{
+ int result;
+ struct device *dev = &cbaf->usb_iface->dev;
+ struct wusb_cbaf_cc_data *ccd;
+ char pr_cdid[WUSB_CKHDID_STRSIZE];
+
+ ccd = cbaf->buffer;
+ *ccd = cbaf_cc_data_defaults;
+ ccd->CHID = cbaf->chid;
+ ccd->CDID = cbaf->cdid;
+ ccd->CK = cbaf->ck;
+ ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups);
+
+ dev_dbg(dev, "Trying to upload CC:\n");
+ ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CHID);
+ dev_dbg(dev, " CHID %s\n", pr_cdid);
+ ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CDID);
+ dev_dbg(dev, " CDID %s\n", pr_cdid);
+ dev_dbg(dev, " Bandgroups 0x%04x\n", cbaf->host_band_groups);
+
+ result = usb_control_msg(
+ cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0),
+ CBAF_REQ_SET_ASSOCIATION_RESPONSE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ ccd, sizeof(*ccd), 1000 /* FIXME: arbitrary */);
+
+ return result;
+}
+
+static ssize_t cbaf_wusb_ck_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_interface *iface = to_usb_interface(dev);
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx",
+ &cbaf->ck.data[0] , &cbaf->ck.data[1],
+ &cbaf->ck.data[2] , &cbaf->ck.data[3],
+ &cbaf->ck.data[4] , &cbaf->ck.data[5],
+ &cbaf->ck.data[6] , &cbaf->ck.data[7],
+ &cbaf->ck.data[8] , &cbaf->ck.data[9],
+ &cbaf->ck.data[10], &cbaf->ck.data[11],
+ &cbaf->ck.data[12], &cbaf->ck.data[13],
+ &cbaf->ck.data[14], &cbaf->ck.data[15]);
+ if (result != 16)
+ return -EINVAL;
+
+ result = cbaf_cc_upload(cbaf);
+ if (result < 0)
+ return result;
+
+ return size;
+}
+static DEVICE_ATTR(wusb_ck, 0600, NULL, cbaf_wusb_ck_store);
+
+static struct attribute *cbaf_dev_attrs[] = {
+ &dev_attr_wusb_host_name.attr,
+ &dev_attr_wusb_host_band_groups.attr,
+ &dev_attr_wusb_chid.attr,
+ &dev_attr_wusb_cdid.attr,
+ &dev_attr_wusb_device_name.attr,
+ &dev_attr_wusb_device_band_groups.attr,
+ &dev_attr_wusb_ck.attr,
+ NULL,
+};
+
+static struct attribute_group cbaf_dev_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = cbaf_dev_attrs,
+};
+
+static int cbaf_probe(struct usb_interface *iface,
+ const struct usb_device_id *id)
+{
+ struct cbaf *cbaf;
+ struct device *dev = &iface->dev;
+ int result = -ENOMEM;
+
+ cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL);
+ if (cbaf == NULL)
+ goto error_kzalloc;
+ cbaf->buffer = kmalloc(512, GFP_KERNEL);
+ if (cbaf->buffer == NULL)
+ goto error_kmalloc_buffer;
+
+ cbaf->buffer_size = 512;
+ cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface));
+ cbaf->usb_iface = usb_get_intf(iface);
+ result = cbaf_check(cbaf);
+ if (result < 0) {
+ dev_err(dev, "This device is not WUSB-CBAF compliant"
+ "and is not supported yet.\n");
+ goto error_check;
+ }
+
+ result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group);
+ if (result < 0) {
+ dev_err(dev, "Can't register sysfs attr group: %d\n", result);
+ goto error_create_group;
+ }
+ usb_set_intfdata(iface, cbaf);
+ return 0;
+
+error_create_group:
+error_check:
+ kfree(cbaf->buffer);
+error_kmalloc_buffer:
+ kfree(cbaf);
+error_kzalloc:
+ return result;
+}
+
+static void cbaf_disconnect(struct usb_interface *iface)
+{
+ struct cbaf *cbaf = usb_get_intfdata(iface);
+ struct device *dev = &iface->dev;
+ sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group);
+ usb_set_intfdata(iface, NULL);
+ usb_put_intf(iface);
+ kfree(cbaf->buffer);
+ /* paranoia: clean up crypto keys */
+ memset(cbaf, 0, sizeof(*cbaf));
+ kfree(cbaf);
+}
+
+static struct usb_device_id cbaf_id_table[] = {
+ { USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, cbaf_id_table);
+
+static struct usb_driver cbaf_driver = {
+ .name = "wusb-cbaf",
+ .id_table = cbaf_id_table,
+ .probe = cbaf_probe,
+ .disconnect = cbaf_disconnect,
+};
+
+static int __init cbaf_driver_init(void)
+{
+ return usb_register(&cbaf_driver);
+}
+module_init(cbaf_driver_init);
+
+static void __exit cbaf_driver_exit(void)
+{
+ usb_deregister(&cbaf_driver);
+}
+module_exit(cbaf_driver_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless USB Cable Based Association");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c
new file mode 100644
index 00000000000..c36c4389baa
--- /dev/null
+++ b/drivers/usb/wusbcore/crypto.c
@@ -0,0 +1,538 @@
+/*
+ * Ultra Wide Band
+ * AES-128 CCM Encryption
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * 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.
+ *
+ *
+ * We don't do any encryption here; we use the Linux Kernel's AES-128
+ * crypto modules to construct keys and payload blocks in a way
+ * defined by WUSB1.0[6]. Check the erratas, as typos are are patched
+ * there.
+ *
+ * Thanks a zillion to John Keys for his help and clarifications over
+ * the designed-by-a-committee text.
+ *
+ * So the idea is that there is this basic Pseudo-Random-Function
+ * defined in WUSB1.0[6.5] which is the core of everything. It works
+ * by tweaking some blocks, AES crypting them and then xoring
+ * something else with them (this seems to be called CBC(AES) -- can
+ * you tell I know jack about crypto?). So we just funnel it into the
+ * Linux Crypto API.
+ *
+ * We leave a crypto test module so we can verify that vectors match,
+ * every now and then.
+ *
+ * Block size: 16 bytes -- AES seems to do things in 'block sizes'. I
+ * am learning a lot...
+ *
+ * Conveniently, some data structures that need to be
+ * funneled through AES are...16 bytes in size!
+ */
+
+#include <linux/crypto.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/uwb.h>
+#include <linux/usb/wusb.h>
+#include <linux/scatterlist.h>
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+
+/*
+ * Block of data, as understood by AES-CCM
+ *
+ * The code assumes this structure is nothing but a 16 byte array
+ * (packed in a struct to avoid common mess ups that I usually do with
+ * arrays and enforcing type checking).
+ */
+struct aes_ccm_block {
+ u8 data[16];
+} __attribute__((packed));
+
+/*
+ * Counter-mode Blocks (WUSB1.0[6.4])
+ *
+ * According to CCM (or so it seems), for the purpose of calculating
+ * the MIC, the message is broken in N counter-mode blocks, B0, B1,
+ * ... BN.
+ *
+ * B0 contains flags, the CCM nonce and l(m).
+ *
+ * B1 contains l(a), the MAC header, the encryption offset and padding.
+ *
+ * If EO is nonzero, additional blocks are built from payload bytes
+ * until EO is exahusted (FIXME: padding to 16 bytes, I guess). The
+ * padding is not xmitted.
+ */
+
+/* WUSB1.0[T6.4] */
+struct aes_ccm_b0 {
+ u8 flags; /* 0x59, per CCM spec */
+ struct aes_ccm_nonce ccm_nonce;
+ __be16 lm;
+} __attribute__((packed));
+
+/* WUSB1.0[T6.5] */
+struct aes_ccm_b1 {
+ __be16 la;
+ u8 mac_header[10];
+ __le16 eo;
+ u8 security_reserved; /* This is always zero */
+ u8 padding; /* 0 */
+} __attribute__((packed));
+
+/*
+ * Encryption Blocks (WUSB1.0[6.4.4])
+ *
+ * CCM uses Ax blocks to generate a keystream with which the MIC and
+ * the message's payload are encoded. A0 always encrypts/decrypts the
+ * MIC. Ax (x>0) are used for the sucesive payload blocks.
+ *
+ * The x is the counter, and is increased for each block.
+ */
+struct aes_ccm_a {
+ u8 flags; /* 0x01, per CCM spec */
+ struct aes_ccm_nonce ccm_nonce;
+ __be16 counter; /* Value of x */
+} __attribute__((packed));
+
+static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
+ size_t size)
+{
+ u8 *bo = _bo;
+ const u8 *bi1 = _bi1, *bi2 = _bi2;
+ size_t itr;
+ for (itr = 0; itr < size; itr++)
+ bo[itr] = bi1[itr] ^ bi2[itr];
+}
+
+/*
+ * CC-MAC function WUSB1.0[6.5]
+ *
+ * Take a data string and produce the encrypted CBC Counter-mode MIC
+ *
+ * Note the names for most function arguments are made to (more or
+ * less) match those used in the pseudo-function definition given in
+ * WUSB1.0[6.5].
+ *
+ * @tfm_cbc: CBC(AES) blkcipher handle (initialized)
+ *
+ * @tfm_aes: AES cipher handle (initialized)
+ *
+ * @mic: buffer for placing the computed MIC (Message Integrity
+ * Code). This is exactly 8 bytes, and we expect the buffer to
+ * be at least eight bytes in length.
+ *
+ * @key: 128 bit symmetric key
+ *
+ * @n: CCM nonce
+ *
+ * @a: ASCII string, 14 bytes long (I guess zero padded if needed;
+ * we use exactly 14 bytes).
+ *
+ * @b: data stream to be processed; cannot be a global or const local
+ * (will confuse the scatterlists)
+ *
+ * @blen: size of b...
+ *
+ * Still not very clear how this is done, but looks like this: we
+ * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with
+ * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we
+ * take the payload and divide it in blocks (16 bytes), xor them with
+ * the previous crypto result (16 bytes) and crypt it, repeat the next
+ * block with the output of the previous one, rinse wash (I guess this
+ * is what AES CBC mode means...but I truly have no idea). So we use
+ * the CBC(AES) blkcipher, that does precisely that. The IV (Initial
+ * Vector) is 16 bytes and is set to zero, so
+ *
+ * See rfc3610. Linux crypto has a CBC implementation, but the
+ * documentation is scarce, to say the least, and the example code is
+ * so intricated that is difficult to understand how things work. Most
+ * of this is guess work -- bite me.
+ *
+ * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and
+ * using the 14 bytes of @a to fill up
+ * b1.{mac_header,e0,security_reserved,padding}.
+ *
+ * NOTE: The definiton of l(a) in WUSB1.0[6.5] vs the definition of
+ * l(m) is orthogonal, they bear no relationship, so it is not
+ * in conflict with the parameter's relation that
+ * WUSB1.0[6.4.2]) defines.
+ *
+ * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in
+ * first errata released on 2005/07.
+ *
+ * NOTE: we need to clean IV to zero at each invocation to make sure
+ * we start with a fresh empty Initial Vector, so that the CBC
+ * works ok.
+ *
+ * NOTE: blen is not aligned to a block size, we'll pad zeros, that's
+ * what sg[4] is for. Maybe there is a smarter way to do this.
+ */
+static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc,
+ struct crypto_cipher *tfm_aes, void *mic,
+ const struct aes_ccm_nonce *n,
+ const struct aes_ccm_label *a, const void *b,
+ size_t blen)
+{
+ int result = 0;
+ struct blkcipher_desc desc;
+ struct aes_ccm_b0 b0;
+ struct aes_ccm_b1 b1;
+ struct aes_ccm_a ax;
+ struct scatterlist sg[4], sg_dst;
+ void *iv, *dst_buf;
+ size_t ivsize, dst_size;
+ const u8 bzero[16] = { 0 };
+ size_t zero_padding;
+
+ d_fnstart(3, NULL, "(tfm_cbc %p, tfm_aes %p, mic %p, "
+ "n %p, a %p, b %p, blen %zu)\n",
+ tfm_cbc, tfm_aes, mic, n, a, b, blen);
+ /*
+ * These checks should be compile time optimized out
+ * ensure @a fills b1's mac_header and following fields
+ */
+ WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la));
+ WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block));
+ WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block));
+ WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block));
+
+ result = -ENOMEM;
+ zero_padding = sizeof(struct aes_ccm_block)
+ - blen % sizeof(struct aes_ccm_block);
+ zero_padding = blen % sizeof(struct aes_ccm_block);
+ if (zero_padding)
+ zero_padding = sizeof(struct aes_ccm_block) - zero_padding;
+ dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding;
+ dst_buf = kzalloc(dst_size, GFP_KERNEL);
+ if (dst_buf == NULL) {
+ printk(KERN_ERR "E: can't alloc destination buffer\n");
+ goto error_dst_buf;
+ }
+
+ iv = crypto_blkcipher_crt(tfm_cbc)->iv;
+ ivsize = crypto_blkcipher_ivsize(tfm_cbc);
+ memset(iv, 0, ivsize);
+
+ /* Setup B0 */
+ b0.flags = 0x59; /* Format B0 */
+ b0.ccm_nonce = *n;
+ b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */
+
+ /* Setup B1
+ *
+ * The WUSB spec is anything but clear! WUSB1.0[6.5]
+ * says that to initialize B1 from A with 'l(a) = blen +
+ * 14'--after clarification, it means to use A's contents
+ * for MAC Header, EO, sec reserved and padding.
+ */
+ b1.la = cpu_to_be16(blen + 14);
+ memcpy(&b1.mac_header, a, sizeof(*a));
+
+ d_printf(4, NULL, "I: B0 (%zu bytes)\n", sizeof(b0));
+ d_dump(4, NULL, &b0, sizeof(b0));
+ d_printf(4, NULL, "I: B1 (%zu bytes)\n", sizeof(b1));
+ d_dump(4, NULL, &b1, sizeof(b1));
+ d_printf(4, NULL, "I: B (%zu bytes)\n", blen);
+ d_dump(4, NULL, b, blen);
+ d_printf(4, NULL, "I: B 0-padding (%zu bytes)\n", zero_padding);
+ d_printf(4, NULL, "D: IV before crypto (%zu)\n", ivsize);
+ d_dump(4, NULL, iv, ivsize);
+
+ sg_init_table(sg, ARRAY_SIZE(sg));
+ sg_set_buf(&sg[0], &b0, sizeof(b0));
+ sg_set_buf(&sg[1], &b1, sizeof(b1));
+ sg_set_buf(&sg[2], b, blen);
+ /* 0 if well behaved :) */
+ sg_set_buf(&sg[3], bzero, zero_padding);
+ sg_init_one(&sg_dst, dst_buf, dst_size);
+
+ desc.tfm = tfm_cbc;
+ desc.flags = 0;
+ result = crypto_blkcipher_encrypt(&desc, &sg_dst, sg, dst_size);
+ if (result < 0) {
+ printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n",
+ result);
+ goto error_cbc_crypt;
+ }
+ d_printf(4, NULL, "D: MIC tag\n");
+ d_dump(4, NULL, iv, ivsize);
+
+ /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5]
+ * The procedure is to AES crypt the A0 block and XOR the MIC
+ * Tag agains it; we only do the first 8 bytes and place it
+ * directly in the destination buffer.
+ *
+ * POS Crypto API: size is assumed to be AES's block size.
+ * Thanks for documenting it -- tip taken from airo.c
+ */
+ ax.flags = 0x01; /* as per WUSB 1.0 spec */
+ ax.ccm_nonce = *n;
+ ax.counter = 0;
+ crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax);
+ bytewise_xor(mic, &ax, iv, 8);
+ d_printf(4, NULL, "D: CTR[MIC]\n");
+ d_dump(4, NULL, &ax, 8);
+ d_printf(4, NULL, "D: CCM-MIC tag\n");
+ d_dump(4, NULL, mic, 8);
+ result = 8;
+error_cbc_crypt:
+ kfree(dst_buf);
+error_dst_buf:
+ d_fnend(3, NULL, "(tfm_cbc %p, tfm_aes %p, mic %p, "
+ "n %p, a %p, b %p, blen %zu)\n",
+ tfm_cbc, tfm_aes, mic, n, a, b, blen);
+ return result;
+}
+
+/*
+ * WUSB Pseudo Random Function (WUSB1.0[6.5])
+ *
+ * @b: buffer to the source data; cannot be a global or const local
+ * (will confuse the scatterlists)
+ */
+ssize_t wusb_prf(void *out, size_t out_size,
+ const u8 key[16], const struct aes_ccm_nonce *_n,
+ const struct aes_ccm_label *a,
+ const void *b, size_t blen, size_t len)
+{
+ ssize_t result, bytes = 0, bitr;
+ struct aes_ccm_nonce n = *_n;
+ struct crypto_blkcipher *tfm_cbc;
+ struct crypto_cipher *tfm_aes;
+ u64 sfn = 0;
+ __le64 sfn_le;
+
+ d_fnstart(3, NULL, "(out %p, out_size %zu, key %p, _n %p, "
+ "a %p, b %p, blen %zu, len %zu)\n", out, out_size,
+ key, _n, a, b, blen, len);
+
+ tfm_cbc = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm_cbc)) {
+ result = PTR_ERR(tfm_cbc);
+ printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result);
+ goto error_alloc_cbc;
+ }
+ result = crypto_blkcipher_setkey(tfm_cbc, key, 16);
+ if (result < 0) {
+ printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result);
+ goto error_setkey_cbc;
+ }
+
+ tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm_aes)) {
+ result = PTR_ERR(tfm_aes);
+ printk(KERN_ERR "E: can't load AES: %d\n", (int)result);
+ goto error_alloc_aes;
+ }
+ result = crypto_cipher_setkey(tfm_aes, key, 16);
+ if (result < 0) {
+ printk(KERN_ERR "E: can't set AES key: %d\n", (int)result);
+ goto error_setkey_aes;
+ }
+
+ for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
+ sfn_le = cpu_to_le64(sfn++);
+ memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
+ result = wusb_ccm_mac(tfm_cbc, tfm_aes, out + bytes,
+ &n, a, b, blen);
+ if (result < 0)
+ goto error_ccm_mac;
+ bytes += result;
+ }
+ result = bytes;
+error_ccm_mac:
+error_setkey_aes:
+ crypto_free_cipher(tfm_aes);
+error_alloc_aes:
+error_setkey_cbc:
+ crypto_free_blkcipher(tfm_cbc);
+error_alloc_cbc:
+ d_fnend(3, NULL, "(out %p, out_size %zu, key %p, _n %p, "
+ "a %p, b %p, blen %zu, len %zu) = %d\n", out, out_size,
+ key, _n, a, b, blen, len, (int)bytes);
+ return result;
+}
+
+/* WUSB1.0[A.2] test vectors */
+static const u8 stv_hsmic_key[16] = {
+ 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
+ 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
+};
+
+static const struct aes_ccm_nonce stv_hsmic_n = {
+ .sfn = { 0 },
+ .tkid = { 0x76, 0x98, 0x01, },
+ .dest_addr = { .data = { 0xbe, 0x00 } },
+ .src_addr = { .data = { 0x76, 0x98 } },
+};
+
+/*
+ * Out-of-band MIC Generation verification code
+ *
+ */
+static int wusb_oob_mic_verify(void)
+{
+ int result;
+ u8 mic[8];
+ /* WUSB1.0[A.2] test vectors
+ *
+ * Need to keep it in the local stack as GCC 4.1.3something
+ * messes up and generates noise.
+ */
+ struct usb_handshake stv_hsmic_hs = {
+ .bMessageNumber = 2,
+ .bStatus = 00,
+ .tTKID = { 0x76, 0x98, 0x01 },
+ .bReserved = 00,
+ .CDID = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+ 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0x3f },
+ .nonce = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ 0x2c, 0x2d, 0x2e, 0x2f },
+ .MIC = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c,
+ 0x14, 0x7b } ,
+ };
+ size_t hs_size;
+
+ result = wusb_oob_mic(mic, stv_hsmic_key, &stv_hsmic_n, &stv_hsmic_hs);
+ if (result < 0)
+ printk(KERN_ERR "E: WUSB OOB MIC test: failed: %d\n", result);
+ else if (memcmp(stv_hsmic_hs.MIC, mic, sizeof(mic))) {
+ printk(KERN_ERR "E: OOB MIC test: "
+ "mismatch between MIC result and WUSB1.0[A2]\n");
+ hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC);
+ printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size);
+ dump_bytes(NULL, &stv_hsmic_hs, hs_size);
+ printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n",
+ sizeof(stv_hsmic_n));
+ dump_bytes(NULL, &stv_hsmic_n, sizeof(stv_hsmic_n));
+ printk(KERN_ERR "E: MIC out:\n");
+ dump_bytes(NULL, mic, sizeof(mic));
+ printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n");
+ dump_bytes(NULL, stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC));
+ result = -EINVAL;
+ } else
+ result = 0;
+ return result;
+}
+
+/*
+ * Test vectors for Key derivation
+ *
+ * These come from WUSB1.0[6.5.1], the vectors in WUSB1.0[A.1]
+ * (errata corrected in 2005/07).
+ */
+static const u8 stv_key_a1[16] __attribute__ ((__aligned__(4))) = {
+ 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87,
+ 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f
+};
+
+static const struct aes_ccm_nonce stv_keydvt_n_a1 = {
+ .sfn = { 0 },
+ .tkid = { 0x76, 0x98, 0x01, },
+ .dest_addr = { .data = { 0xbe, 0x00 } },
+ .src_addr = { .data = { 0x76, 0x98 } },
+};
+
+static const struct wusb_keydvt_out stv_keydvt_out_a1 = {
+ .kck = {
+ 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
+ 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
+ },
+ .ptk = {
+ 0xc8, 0x70, 0x62, 0x82, 0xb6, 0x7c, 0xe9, 0x06,
+ 0x7b, 0xc5, 0x25, 0x69, 0xf2, 0x36, 0x61, 0x2d
+ }
+};
+
+/*
+ * Performa a test to make sure we match the vectors defined in
+ * WUSB1.0[A.1](Errata2006/12)
+ */
+static int wusb_key_derive_verify(void)
+{
+ int result = 0;
+ struct wusb_keydvt_out keydvt_out;
+ /* These come from WUSB1.0[A.1] + 2006/12 errata
+ * NOTE: can't make this const or global -- somehow it seems
+ * the scatterlists for crypto get confused and we get
+ * bad data. There is no doc on this... */
+ struct wusb_keydvt_in stv_keydvt_in_a1 = {
+ .hnonce = {
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
+ },
+ .dnonce = {
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
+ }
+ };
+
+ result = wusb_key_derive(&keydvt_out, stv_key_a1, &stv_keydvt_n_a1,
+ &stv_keydvt_in_a1);
+ if (result < 0)
+ printk(KERN_ERR "E: WUSB key derivation test: "
+ "derivation failed: %d\n", result);
+ if (memcmp(&stv_keydvt_out_a1, &keydvt_out, sizeof(keydvt_out))) {
+ printk(KERN_ERR "E: WUSB key derivation test: "
+ "mismatch between key derivation result "
+ "and WUSB1.0[A1] Errata 2006/12\n");
+ printk(KERN_ERR "E: keydvt in: key (%zu bytes)\n",
+ sizeof(stv_key_a1));
+ dump_bytes(NULL, stv_key_a1, sizeof(stv_key_a1));
+ printk(KERN_ERR "E: keydvt in: nonce (%zu bytes)\n",
+ sizeof(stv_keydvt_n_a1));
+ dump_bytes(NULL, &stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1));
+ printk(KERN_ERR "E: keydvt in: hnonce & dnonce (%zu bytes)\n",
+ sizeof(stv_keydvt_in_a1));
+ dump_bytes(NULL, &stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1));
+ printk(KERN_ERR "E: keydvt out: KCK\n");
+ dump_bytes(NULL, &keydvt_out.kck, sizeof(keydvt_out.kck));
+ printk(KERN_ERR "E: keydvt out: PTK\n");
+ dump_bytes(NULL, &keydvt_out.ptk, sizeof(keydvt_out.ptk));
+ result = -EINVAL;
+ } else
+ result = 0;
+ return result;
+}
+
+/*
+ * Initialize crypto system
+ *
+ * FIXME: we do nothing now, other than verifying. Later on we'll
+ * cache the encryption stuff, so that's why we have a separate init.
+ */
+int wusb_crypto_init(void)
+{
+ int result;
+
+ result = wusb_key_derive_verify();
+ if (result < 0)
+ return result;
+ return wusb_oob_mic_verify();
+}
+
+void wusb_crypto_exit(void)
+{
+ /* FIXME: free cached crypto transforms */
+}
diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c
new file mode 100644
index 00000000000..7897a19652e
--- /dev/null
+++ b/drivers/usb/wusbcore/dev-sysfs.c
@@ -0,0 +1,143 @@
+/*
+ * WUSB devices
+ * sysfs bindings
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * 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.
+ *
+ *
+ * Get them out of the way...
+ */
+
+#include <linux/jiffies.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include "wusbhc.h"
+
+#undef D_LOCAL
+#define D_LOCAL 4
+#include <linux/uwb/debug.h>
+
+static ssize_t wusb_disconnect_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct usb_device *usb_dev;
+ struct wusbhc *wusbhc;
+ unsigned command;
+ u8 port_idx;
+
+ if (sscanf(buf, "%u", &command) != 1)
+ return -EINVAL;
+ if (command == 0)
+ return size;
+ usb_dev = to_usb_device(dev);
+ wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+ if (wusbhc == NULL)
+ return -ENODEV;
+
+ mutex_lock(&wusbhc->mutex);
+ port_idx = wusb_port_no_to_idx(usb_dev->portnum);
+ __wusbhc_dev_disable(wusbhc, port_idx);
+ mutex_unlock(&wusbhc->mutex);
+ wusbhc_put(wusbhc);
+ return size;
+}
+static DEVICE_ATTR(wusb_disconnect, 0200, NULL, wusb_disconnect_store);
+
+static ssize_t wusb_cdid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t result;
+ struct wusb_dev *wusb_dev;
+
+ wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev));
+ if (wusb_dev == NULL)
+ return -ENODEV;
+ result = ckhdid_printf(buf, PAGE_SIZE, &wusb_dev->cdid);
+ strcat(buf, "\n");
+ wusb_dev_put(wusb_dev);
+ return result + 1;
+}
+static DEVICE_ATTR(wusb_cdid, 0444, wusb_cdid_show, NULL);
+
+static ssize_t wusb_ck_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int result;
+ struct usb_device *usb_dev;
+ struct wusbhc *wusbhc;
+ struct wusb_ckhdid ck;
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx\n",
+ &ck.data[0] , &ck.data[1],
+ &ck.data[2] , &ck.data[3],
+ &ck.data[4] , &ck.data[5],
+ &ck.data[6] , &ck.data[7],
+ &ck.data[8] , &ck.data[9],
+ &ck.data[10], &ck.data[11],
+ &ck.data[12], &ck.data[13],
+ &ck.data[14], &ck.data[15]);
+ if (result != 16)
+ return -EINVAL;
+
+ usb_dev = to_usb_device(dev);
+ wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+ if (wusbhc == NULL)
+ return -ENODEV;
+ result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck);
+ memset(&ck, 0, sizeof(ck));
+ wusbhc_put(wusbhc);
+ return result < 0 ? result : size;
+}
+static DEVICE_ATTR(wusb_ck, 0200, NULL, wusb_ck_store);
+
+static struct attribute *wusb_dev_attrs[] = {
+ &dev_attr_wusb_disconnect.attr,
+ &dev_attr_wusb_cdid.attr,
+ &dev_attr_wusb_ck.attr,
+ NULL,
+};
+
+static struct attribute_group wusb_dev_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = wusb_dev_attrs,
+};
+
+int wusb_dev_sysfs_add(struct wusbhc *wusbhc, struct usb_device *usb_dev,
+ struct wusb_dev *wusb_dev)
+{
+ int result = sysfs_create_group(&usb_dev->dev.kobj,
+ &wusb_dev_attr_group);
+ struct device *dev = &usb_dev->dev;
+ if (result < 0)
+ dev_err(dev, "Cannot register WUSB-dev attributes: %d\n",
+ result);
+ return result;
+}
+
+void wusb_dev_sysfs_rm(struct wusb_dev *wusb_dev)
+{
+ struct usb_device *usb_dev = wusb_dev->usb_dev;
+ if (usb_dev)
+ sysfs_remove_group(&usb_dev->dev.kobj, &wusb_dev_attr_group);
+}
diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c
new file mode 100644
index 00000000000..f45d777bef3
--- /dev/null
+++ b/drivers/usb/wusbcore/devconnect.c
@@ -0,0 +1,1297 @@
+/*
+ * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
+ * Device Connect handling
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ * FIXME: this file needs to be broken up, it's grown too big
+ *
+ *
+ * WUSB1.0[7.1, 7.5.1, ]
+ *
+ * WUSB device connection is kind of messy. Some background:
+ *
+ * When a device wants to connect it scans the UWB radio channels
+ * looking for a WUSB Channel; a WUSB channel is defined by MMCs
+ * (Micro Managed Commands or something like that) [see
+ * Design-overview for more on this] .
+ *
+ * So, device scans the radio, finds MMCs and thus a host and checks
+ * when the next DNTS is. It sends a Device Notification Connect
+ * (DN_Connect); the host picks it up (through nep.c and notif.c, ends
+ * up in wusb_devconnect_ack(), which creates a wusb_dev structure in
+ * wusbhc->port[port_number].wusb_dev), assigns an unauth address
+ * to the device (this means from 0x80 to 0xfe) and sends, in the MMC
+ * a Connect Ack Information Element (ConnAck IE).
+ *
+ * So now the device now has a WUSB address. From now on, we use
+ * that to talk to it in the RPipes.
+ *
+ * ASSUMPTIONS:
+ *
+ * - We use the the as device address the port number where it is
+ * connected (port 0 doesn't exist). For unauth, it is 128 + that.
+ *
+ * ROADMAP:
+ *
+ * This file contains the logic for doing that--entry points:
+ *
+ * wusb_devconnect_ack() Ack a device until _acked() called.
+ * Called by notif.c:wusb_handle_dn_connect()
+ * when a DN_Connect is received.
+ *
+ * wusbhc_devconnect_auth() Called by rh.c:wusbhc_rh_port_reset() when
+ * doing the device connect sequence.
+ *
+ * wusb_devconnect_acked() Ack done, release resources.
+ *
+ * wusb_handle_dn_alive() Called by notif.c:wusb_handle_dn()
+ * for processing a DN_Alive pong from a device.
+ *
+ * wusb_handle_dn_disconnect()Called by notif.c:wusb_handle_dn() to
+ * process a disconenct request from a
+ * device.
+ *
+ * wusb_dev_reset() Called by rh.c:wusbhc_rh_port_reset() when
+ * resetting a device.
+ *
+ * __wusb_dev_disable() Called by rh.c:wusbhc_rh_clear_port_feat() when
+ * disabling a port.
+ *
+ * wusb_devconnect_create() Called when creating the host by
+ * lc.c:wusbhc_create().
+ *
+ * wusb_devconnect_destroy() Cleanup called removing the host. Called
+ * by lc.c:wusbhc_destroy().
+ *
+ * Each Wireless USB host maintains a list of DN_Connect requests
+ * (actually we maintain a list of pending Connect Acks, the
+ * wusbhc->ca_list).
+ *
+ * LIFE CYCLE OF port->wusb_dev
+ *
+ * Before the @wusbhc structure put()s the reference it owns for
+ * port->wusb_dev [and clean the wusb_dev pointer], it needs to
+ * lock @wusbhc->mutex.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include "wusbhc.h"
+
+#undef D_LOCAL
+#define D_LOCAL 1
+#include <linux/uwb/debug.h>
+
+static void wusbhc_devconnect_acked_work(struct work_struct *work);
+
+static void wusb_dev_free(struct wusb_dev *wusb_dev)
+{
+ if (wusb_dev) {
+ kfree(wusb_dev->set_gtk_req);
+ usb_free_urb(wusb_dev->set_gtk_urb);
+ kfree(wusb_dev);
+ }
+}
+
+static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)
+{
+ struct wusb_dev *wusb_dev;
+ struct urb *urb;
+ struct usb_ctrlrequest *req;
+
+ wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL);
+ if (wusb_dev == NULL)
+ goto err;
+
+ wusb_dev->wusbhc = wusbhc;
+
+ INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work);
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (urb == NULL)
+ goto err;
+
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (req == NULL)
+ goto err;
+
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+ req->bRequest = USB_REQ_SET_DESCRIPTOR;
+ req->wValue = cpu_to_le16(USB_DT_KEY << 8 | wusbhc->gtk_index);
+ req->wIndex = 0;
+ req->wLength = cpu_to_le16(wusbhc->gtk.descr.bLength);
+
+ wusb_dev->set_gtk_urb = urb;
+ wusb_dev->set_gtk_req = req;
+
+ return wusb_dev;
+err:
+ wusb_dev_free(wusb_dev);
+ return NULL;
+}
+
+
+/*
+ * Using the Connect-Ack list, fill out the @wusbhc Connect-Ack WUSB IE
+ * properly so that it can be added to the MMC.
+ *
+ * We just get the @wusbhc->ca_list and fill out the first four ones or
+ * less (per-spec WUSB1.0[7.5, before T7-38). If the ConnectAck WUSB
+ * IE is not allocated, we alloc it.
+ *
+ * @wusbhc->mutex must be taken
+ */
+static void wusbhc_fill_cack_ie(struct wusbhc *wusbhc)
+{
+ unsigned cnt;
+ struct wusb_dev *dev_itr;
+ struct wuie_connect_ack *cack_ie;
+
+ cack_ie = &wusbhc->cack_ie;
+ cnt = 0;
+ list_for_each_entry(dev_itr, &wusbhc->cack_list, cack_node) {
+ cack_ie->blk[cnt].CDID = dev_itr->cdid;
+ cack_ie->blk[cnt].bDeviceAddress = dev_itr->addr;
+ if (++cnt >= WUIE_ELT_MAX)
+ break;
+ }
+ cack_ie->hdr.bLength = sizeof(cack_ie->hdr)
+ + cnt * sizeof(cack_ie->blk[0]);
+}
+
+/*
+ * Register a new device that wants to connect
+ *
+ * A new device wants to connect, so we add it to the Connect-Ack
+ * list. We give it an address in the unauthorized range (bit 8 set);
+ * user space will have to drive authorization further on.
+ *
+ * @dev_addr: address to use for the device (which is also the port
+ * number).
+ *
+ * @wusbhc->mutex must be taken
+ */
+static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc,
+ struct wusb_dn_connect *dnc,
+ const char *pr_cdid, u8 port_idx)
+{
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev;
+ int new_connection = wusb_dn_connect_new_connection(dnc);
+ u8 dev_addr;
+ int result;
+
+ /* Is it registered already? */
+ list_for_each_entry(wusb_dev, &wusbhc->cack_list, cack_node)
+ if (!memcmp(&wusb_dev->cdid, &dnc->CDID,
+ sizeof(wusb_dev->cdid)))
+ return wusb_dev;
+ /* We don't have it, create an entry, register it */
+ wusb_dev = wusb_dev_alloc(wusbhc);
+ if (wusb_dev == NULL)
+ return NULL;
+ wusb_dev_init(wusb_dev);
+ wusb_dev->cdid = dnc->CDID;
+ wusb_dev->port_idx = port_idx;
+
+ /*
+ * Devices are always available within the cluster reservation
+ * and since the hardware will take the intersection of the
+ * per-device availability and the cluster reservation, the
+ * per-device availability can simply be set to always
+ * available.
+ */
+ bitmap_fill(wusb_dev->availability.bm, UWB_NUM_MAS);
+
+ /* FIXME: handle reconnects instead of assuming connects are
+ always new. */
+ if (1 && new_connection == 0)
+ new_connection = 1;
+ if (new_connection) {
+ dev_addr = (port_idx + 2) | WUSB_DEV_ADDR_UNAUTH;
+
+ dev_info(dev, "Connecting new WUSB device to address %u, "
+ "port %u\n", dev_addr, port_idx);
+
+ result = wusb_set_dev_addr(wusbhc, wusb_dev, dev_addr);
+ if (result < 0)
+ return NULL;
+ }
+ wusb_dev->entry_ts = jiffies;
+ list_add_tail(&wusb_dev->cack_node, &wusbhc->cack_list);
+ wusbhc->cack_count++;
+ wusbhc_fill_cack_ie(wusbhc);
+ return wusb_dev;
+}
+
+/*
+ * Remove a Connect-Ack context entry from the HCs view
+ *
+ * @wusbhc->mutex must be taken
+ */
+static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ struct device *dev = wusbhc->dev;
+ d_fnstart(3, dev, "(wusbhc %p wusb_dev %p)\n", wusbhc, wusb_dev);
+ list_del_init(&wusb_dev->cack_node);
+ wusbhc->cack_count--;
+ wusbhc_fill_cack_ie(wusbhc);
+ d_fnend(3, dev, "(wusbhc %p wusb_dev %p) = void\n", wusbhc, wusb_dev);
+}
+
+/*
+ * @wusbhc->mutex must be taken */
+static
+void wusbhc_devconnect_acked(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ struct device *dev = wusbhc->dev;
+ d_fnstart(3, dev, "(wusbhc %p wusb_dev %p)\n", wusbhc, wusb_dev);
+ wusbhc_cack_rm(wusbhc, wusb_dev);
+ if (wusbhc->cack_count)
+ wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
+ else
+ wusbhc_mmcie_rm(wusbhc, &wusbhc->cack_ie.hdr);
+ d_fnend(3, dev, "(wusbhc %p wusb_dev %p) = void\n", wusbhc, wusb_dev);
+}
+
+static void wusbhc_devconnect_acked_work(struct work_struct *work)
+{
+ struct wusb_dev *wusb_dev = container_of(work, struct wusb_dev,
+ devconnect_acked_work);
+ struct wusbhc *wusbhc = wusb_dev->wusbhc;
+
+ mutex_lock(&wusbhc->mutex);
+ wusbhc_devconnect_acked(wusbhc, wusb_dev);
+ mutex_unlock(&wusbhc->mutex);
+}
+
+/*
+ * Ack a device for connection
+ *
+ * FIXME: docs
+ *
+ * @pr_cdid: Printable CDID...hex Use @dnc->cdid for the real deal.
+ *
+ * So we get the connect ack IE (may have been allocated already),
+ * find an empty connect block, an empty virtual port, create an
+ * address with it (see below), make it an unauth addr [bit 7 set] and
+ * set the MMC.
+ *
+ * Addresses: because WUSB hosts have no downstream hubs, we can do a
+ * 1:1 mapping between 'port number' and device
+ * address. This simplifies many things, as during this
+ * initial connect phase the USB stack has no knoledge of
+ * the device and hasn't assigned an address yet--we know
+ * USB's choose_address() will use the same euristics we
+ * use here, so we can assume which address will be assigned.
+ *
+ * USB stack always assigns address 1 to the root hub, so
+ * to the port number we add 2 (thus virtual port #0 is
+ * addr #2).
+ *
+ * @wusbhc shall be referenced
+ */
+static
+void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc,
+ const char *pr_cdid)
+{
+ int result;
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev;
+ struct wusb_port *port;
+ unsigned idx, devnum;
+
+ d_fnstart(3, dev, "(%p, %p, %s)\n", wusbhc, dnc, pr_cdid);
+ mutex_lock(&wusbhc->mutex);
+
+ /* Check we are not handling it already */
+ for (idx = 0; idx < wusbhc->ports_max; idx++) {
+ port = wusb_port_by_idx(wusbhc, idx);
+ if (port->wusb_dev
+ && memcmp(&dnc->CDID, &port->wusb_dev->cdid, sizeof(dnc->CDID)) == 0)
+ goto error_unlock;
+ }
+ /* Look up those fake ports we have for a free one */
+ for (idx = 0; idx < wusbhc->ports_max; idx++) {
+ port = wusb_port_by_idx(wusbhc, idx);
+ if ((port->status & USB_PORT_STAT_POWER)
+ && !(port->status & USB_PORT_STAT_CONNECTION))
+ break;
+ }
+ if (idx >= wusbhc->ports_max) {
+ dev_err(dev, "Host controller can't connect more devices "
+ "(%u already connected); device %s rejected\n",
+ wusbhc->ports_max, pr_cdid);
+ /* NOTE: we could send a WUIE_Disconnect here, but we haven't
+ * event acked, so the device will eventually timeout the
+ * connection, right? */
+ goto error_unlock;
+ }
+
+ devnum = idx + 2;
+
+ /* Make sure we are using no crypto on that "virtual port" */
+ wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0);
+
+ /* Grab a filled in Connect-Ack context, fill out the
+ * Connect-Ack Wireless USB IE, set the MMC */
+ wusb_dev = wusbhc_cack_add(wusbhc, dnc, pr_cdid, idx);
+ if (wusb_dev == NULL)
+ goto error_unlock;
+ result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
+ if (result < 0)
+ goto error_unlock;
+ /* Give the device at least 2ms (WUSB1.0[7.5.1p3]), let's do
+ * three for a good measure */
+ msleep(3);
+ port->wusb_dev = wusb_dev;
+ port->status |= USB_PORT_STAT_CONNECTION;
+ port->change |= USB_PORT_STAT_C_CONNECTION;
+ port->reset_count = 0;
+ /* Now the port status changed to connected; khubd will
+ * pick the change up and try to reset the port to bring it to
+ * the enabled state--so this process returns up to the stack
+ * and it calls back into wusbhc_rh_port_reset() who will call
+ * devconnect_auth().
+ */
+error_unlock:
+ mutex_unlock(&wusbhc->mutex);
+ d_fnend(3, dev, "(%p, %p, %s) = void\n", wusbhc, dnc, pr_cdid);
+ return;
+
+}
+
+/*
+ * Disconnect a Wireless USB device from its fake port
+ *
+ * Marks the port as disconnected so that khubd can pick up the change
+ * and drops our knowledge about the device.
+ *
+ * Assumes there is a device connected
+ *
+ * @port_index: zero based port number
+ *
+ * NOTE: @wusbhc->mutex is locked
+ *
+ * WARNING: From here it is not very safe to access anything hanging off
+ * wusb_dev
+ */
+static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc,
+ struct wusb_port *port)
+{
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev = port->wusb_dev;
+
+ d_fnstart(3, dev, "(wusbhc %p, port %p)\n", wusbhc, port);
+ port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE
+ | USB_PORT_STAT_SUSPEND | USB_PORT_STAT_RESET
+ | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
+ port->change |= USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE;
+ if (wusb_dev) {
+ if (!list_empty(&wusb_dev->cack_node))
+ list_del_init(&wusb_dev->cack_node);
+ /* For the one in cack_add() */
+ wusb_dev_put(wusb_dev);
+ }
+ port->wusb_dev = NULL;
+ /* don't reset the reset_count to zero or wusbhc_rh_port_reset will get
+ * confused! We only reset to zero when we connect a new device.
+ */
+
+ /* After a device disconnects, change the GTK (see [WUSB]
+ * section 6.2.11.2). */
+ wusbhc_gtk_rekey(wusbhc);
+
+ d_fnend(3, dev, "(wusbhc %p, port %p) = void\n", wusbhc, port);
+ /* The Wireless USB part has forgotten about the device already; now
+ * khubd's timer will pick up the disconnection and remove the USB
+ * device from the system
+ */
+}
+
+/*
+ * Authenticate a device into the WUSB Cluster
+ *
+ * Called from the Root Hub code (rh.c:wusbhc_rh_port_reset()) when
+ * asking for a reset on a port that is not enabled (ie: first connect
+ * on the port).
+ *
+ * Performs the 4way handshake to allow the device to comunicate w/ the
+ * WUSB Cluster securely; once done, issue a request to the device for
+ * it to change to address 0.
+ *
+ * This mimics the reset step of Wired USB that once resetting a
+ * device, leaves the port in enabled state and the dev with the
+ * default address (0).
+ *
+ * WUSB1.0[7.1.2]
+ *
+ * @port_idx: port where the change happened--This is the index into
+ * the wusbhc port array, not the USB port number.
+ */
+int wusbhc_devconnect_auth(struct wusbhc *wusbhc, u8 port_idx)
+{
+ struct device *dev = wusbhc->dev;
+ struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx);
+
+ d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx);
+ port->status &= ~USB_PORT_STAT_RESET;
+ port->status |= USB_PORT_STAT_ENABLE;
+ port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE;
+ d_fnend(3, dev, "(%p, %u) = 0\n", wusbhc, port_idx);
+ return 0;
+}
+
+/*
+ * Refresh the list of keep alives to emit in the MMC
+ *
+ * Some devices don't respond to keep alives unless they've been
+ * authenticated, so skip unauthenticated devices.
+ *
+ * We only publish the first four devices that have a coming timeout
+ * condition. Then when we are done processing those, we go for the
+ * next ones. We ignore the ones that have timed out already (they'll
+ * be purged).
+ *
+ * This might cause the first devices to timeout the last devices in
+ * the port array...FIXME: come up with a better algorithm?
+ *
+ * Note we can't do much about MMC's ops errors; we hope next refresh
+ * will kind of handle it.
+ *
+ * NOTE: @wusbhc->mutex is locked
+ */
+static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
+{
+ struct device *dev = wusbhc->dev;
+ unsigned cnt;
+ struct wusb_dev *wusb_dev;
+ struct wusb_port *wusb_port;
+ struct wuie_keep_alive *ie = &wusbhc->keep_alive_ie;
+ unsigned keep_alives, old_keep_alives;
+
+ old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr);
+ keep_alives = 0;
+ for (cnt = 0;
+ keep_alives <= WUIE_ELT_MAX && cnt < wusbhc->ports_max;
+ cnt++) {
+ unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout);
+
+ wusb_port = wusb_port_by_idx(wusbhc, cnt);
+ wusb_dev = wusb_port->wusb_dev;
+
+ if (wusb_dev == NULL)
+ continue;
+ if (wusb_dev->usb_dev == NULL || !wusb_dev->usb_dev->authenticated)
+ continue;
+
+ if (time_after(jiffies, wusb_dev->entry_ts + tt)) {
+ dev_err(dev, "KEEPALIVE: device %u timed out\n",
+ wusb_dev->addr);
+ __wusbhc_dev_disconnect(wusbhc, wusb_port);
+ } else if (time_after(jiffies, wusb_dev->entry_ts + tt/2)) {
+ /* Approaching timeout cut out, need to refresh */
+ ie->bDeviceAddress[keep_alives++] = wusb_dev->addr;
+ }
+ }
+ if (keep_alives & 0x1) /* pad to even number ([WUSB] section 7.5.9) */
+ ie->bDeviceAddress[keep_alives++] = 0x7f;
+ ie->hdr.bLength = sizeof(ie->hdr) +
+ keep_alives*sizeof(ie->bDeviceAddress[0]);
+ if (keep_alives > 0)
+ wusbhc_mmcie_set(wusbhc, 10, 5, &ie->hdr);
+ else if (old_keep_alives != 0)
+ wusbhc_mmcie_rm(wusbhc, &ie->hdr);
+}
+
+/*
+ * Do a run through all devices checking for timeouts
+ */
+static void wusbhc_keep_alive_run(struct work_struct *ws)
+{
+ struct delayed_work *dw =
+ container_of(ws, struct delayed_work, work);
+ struct wusbhc *wusbhc =
+ container_of(dw, struct wusbhc, keep_alive_timer);
+
+ d_fnstart(5, wusbhc->dev, "(wusbhc %p)\n", wusbhc);
+ if (wusbhc->active) {
+ mutex_lock(&wusbhc->mutex);
+ __wusbhc_keep_alive(wusbhc);
+ mutex_unlock(&wusbhc->mutex);
+ queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
+ (wusbhc->trust_timeout * CONFIG_HZ)/1000/2);
+ }
+ d_fnend(5, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc);
+ return;
+}
+
+/*
+ * Find the wusb_dev from its device address.
+ *
+ * The device can be found directly from the address (see
+ * wusb_cack_add() for where the device address is set to port_idx
+ * +2), except when the address is zero.
+ */
+static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
+{
+ int p;
+
+ if (addr == 0xff) /* unconnected */
+ return NULL;
+
+ if (addr > 0) {
+ int port = (addr & ~0x80) - 2;
+ if (port < 0 || port >= wusbhc->ports_max)
+ return NULL;
+ return wusb_port_by_idx(wusbhc, port)->wusb_dev;
+ }
+
+ /* Look for the device with address 0. */
+ for (p = 0; p < wusbhc->ports_max; p++) {
+ struct wusb_dev *wusb_dev = wusb_port_by_idx(wusbhc, p)->wusb_dev;
+ if (wusb_dev && wusb_dev->addr == addr)
+ return wusb_dev;
+ }
+ return NULL;
+}
+
+/*
+ * Handle a DN_Alive notification (WUSB1.0[7.6.1])
+ *
+ * This just updates the device activity timestamp and then refreshes
+ * the keep alive IE.
+ *
+ * @wusbhc shall be referenced and unlocked
+ */
+static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ struct device *dev = wusbhc->dev;
+
+ d_printf(2, dev, "DN ALIVE: device 0x%02x pong\n", wusb_dev->addr);
+
+ mutex_lock(&wusbhc->mutex);
+ wusb_dev->entry_ts = jiffies;
+ __wusbhc_keep_alive(wusbhc);
+ mutex_unlock(&wusbhc->mutex);
+}
+
+/*
+ * Handle a DN_Connect notification (WUSB1.0[7.6.1])
+ *
+ * @wusbhc
+ * @pkt_hdr
+ * @size: Size of the buffer where the notification resides; if the
+ * notification data suggests there should be more data than
+ * available, an error will be signaled and the whole buffer
+ * consumed.
+ *
+ * @wusbhc->mutex shall be held
+ */
+static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
+ struct wusb_dn_hdr *dn_hdr,
+ size_t size)
+{
+ struct device *dev = wusbhc->dev;
+ struct wusb_dn_connect *dnc;
+ char pr_cdid[WUSB_CKHDID_STRSIZE];
+ static const char *beacon_behaviour[] = {
+ "reserved",
+ "self-beacon",
+ "directed-beacon",
+ "no-beacon"
+ };
+
+ d_fnstart(3, dev, "(%p, %p, %zu)\n", wusbhc, dn_hdr, size);
+ if (size < sizeof(*dnc)) {
+ dev_err(dev, "DN CONNECT: short notification (%zu < %zu)\n",
+ size, sizeof(*dnc));
+ goto out;
+ }
+
+ dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr);
+ ckhdid_printf(pr_cdid, sizeof(pr_cdid), &dnc->CDID);
+ dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n",
+ pr_cdid,
+ wusb_dn_connect_prev_dev_addr(dnc),
+ beacon_behaviour[wusb_dn_connect_beacon_behavior(dnc)],
+ wusb_dn_connect_new_connection(dnc) ? "connect" : "reconnect");
+ /* ACK the connect */
+ wusbhc_devconnect_ack(wusbhc, dnc, pr_cdid);
+out:
+ d_fnend(3, dev, "(%p, %p, %zu) = void\n",
+ wusbhc, dn_hdr, size);
+ return;
+}
+
+/*
+ * Handle a DN_Disconnect notification (WUSB1.0[7.6.1])
+ *
+ * Device is going down -- do the disconnect.
+ *
+ * @wusbhc shall be referenced and unlocked
+ */
+static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ struct device *dev = wusbhc->dev;
+
+ dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", wusb_dev->addr);
+
+ mutex_lock(&wusbhc->mutex);
+ __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, wusb_dev->port_idx));
+ mutex_unlock(&wusbhc->mutex);
+}
+
+/*
+ * Reset a WUSB device on a HWA
+ *
+ * @wusbhc
+ * @port_idx Index of the port where the device is
+ *
+ * In Wireless USB, a reset is more or less equivalent to a full
+ * disconnect; so we just do a full disconnect and send the device a
+ * Device Reset IE (WUSB1.0[7.5.11]) giving it a few millisecs (6 MMCs).
+ *
+ * @wusbhc should be refcounted and unlocked
+ */
+int wusbhc_dev_reset(struct wusbhc *wusbhc, u8 port_idx)
+{
+ int result;
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev;
+ struct wuie_reset *ie;
+
+ d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx);
+ mutex_lock(&wusbhc->mutex);
+ result = 0;
+ wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
+ if (wusb_dev == NULL) {
+ /* reset no device? ignore */
+ dev_dbg(dev, "RESET: no device at port %u, ignoring\n",
+ port_idx);
+ goto error_unlock;
+ }
+ result = -ENOMEM;
+ ie = kzalloc(sizeof(*ie), GFP_KERNEL);
+ if (ie == NULL)
+ goto error_unlock;
+ ie->hdr.bLength = sizeof(ie->hdr) + sizeof(ie->CDID);
+ ie->hdr.bIEIdentifier = WUIE_ID_RESET_DEVICE;
+ ie->CDID = wusb_dev->cdid;
+ result = wusbhc_mmcie_set(wusbhc, 0xff, 6, &ie->hdr);
+ if (result < 0) {
+ dev_err(dev, "RESET: cant's set MMC: %d\n", result);
+ goto error_kfree;
+ }
+ __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
+
+ /* 120ms, hopefully 6 MMCs (FIXME) */
+ msleep(120);
+ wusbhc_mmcie_rm(wusbhc, &ie->hdr);
+error_kfree:
+ kfree(ie);
+error_unlock:
+ mutex_unlock(&wusbhc->mutex);
+ d_fnend(3, dev, "(%p, %u) = %d\n", wusbhc, port_idx, result);
+ return result;
+}
+
+/*
+ * Handle a Device Notification coming a host
+ *
+ * The Device Notification comes from a host (HWA, DWA or WHCI)
+ * wrapped in a set of headers. Somebody else has peeled off those
+ * headers for us and we just get one Device Notifications.
+ *
+ * Invalid DNs (e.g., too short) are discarded.
+ *
+ * @wusbhc shall be referenced
+ *
+ * FIXMES:
+ * - implement priorities as in WUSB1.0[Table 7-55]?
+ */
+void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,
+ struct wusb_dn_hdr *dn_hdr, size_t size)
+{
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev;
+
+ d_fnstart(3, dev, "(%p, %p)\n", wusbhc, dn_hdr);
+
+ if (size < sizeof(struct wusb_dn_hdr)) {
+ dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
+ (int)size, (int)sizeof(struct wusb_dn_hdr));
+ goto out;
+ }
+
+ wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
+ if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) {
+ dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n",
+ dn_hdr->bType, srcaddr);
+ goto out;
+ }
+
+ switch (dn_hdr->bType) {
+ case WUSB_DN_CONNECT:
+ wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
+ break;
+ case WUSB_DN_ALIVE:
+ wusbhc_handle_dn_alive(wusbhc, wusb_dev);
+ break;
+ case WUSB_DN_DISCONNECT:
+ wusbhc_handle_dn_disconnect(wusbhc, wusb_dev);
+ break;
+ case WUSB_DN_MASAVAILCHANGED:
+ case WUSB_DN_RWAKE:
+ case WUSB_DN_SLEEP:
+ /* FIXME: handle these DNs. */
+ break;
+ case WUSB_DN_EPRDY:
+ /* The hardware handles these. */
+ break;
+ default:
+ dev_warn(dev, "unknown DN %u (%d octets) from %u\n",
+ dn_hdr->bType, (int)size, srcaddr);
+ }
+out:
+ d_fnend(3, dev, "(%p, %p) = void\n", wusbhc, dn_hdr);
+ return;
+}
+EXPORT_SYMBOL_GPL(wusbhc_handle_dn);
+
+/*
+ * Disconnect a WUSB device from a the cluster
+ *
+ * @wusbhc
+ * @port Fake port where the device is (wusbhc index, not USB port number).
+ *
+ * In Wireless USB, a disconnect is basically telling the device he is
+ * being disconnected and forgetting about him.
+ *
+ * We send the device a Device Disconnect IE (WUSB1.0[7.5.11]) for 100
+ * ms and then keep going.
+ *
+ * We don't do much in case of error; we always pretend we disabled
+ * the port and disconnected the device. If physically the request
+ * didn't get there (many things can fail in the way there), the stack
+ * will reject the device's communication attempts.
+ *
+ * @wusbhc should be refcounted and locked
+ */
+void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port_idx)
+{
+ int result;
+ struct device *dev = wusbhc->dev;
+ struct wusb_dev *wusb_dev;
+ struct wuie_disconnect *ie;
+
+ d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx);
+ result = 0;
+ wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
+ if (wusb_dev == NULL) {
+ /* reset no device? ignore */
+ dev_dbg(dev, "DISCONNECT: no device at port %u, ignoring\n",
+ port_idx);
+ goto error;
+ }
+ __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
+
+ result = -ENOMEM;
+ ie = kzalloc(sizeof(*ie), GFP_KERNEL);
+ if (ie == NULL)
+ goto error;
+ ie->hdr.bLength = sizeof(*ie);
+ ie->hdr.bIEIdentifier = WUIE_ID_DEVICE_DISCONNECT;
+ ie->bDeviceAddress = wusb_dev->addr;
+ result = wusbhc_mmcie_set(wusbhc, 0, 0, &ie->hdr);
+ if (result < 0) {
+ dev_err(dev, "DISCONNECT: can't set MMC: %d\n", result);
+ goto error_kfree;
+ }
+
+ /* 120ms, hopefully 6 MMCs */
+ msleep(100);
+ wusbhc_mmcie_rm(wusbhc, &ie->hdr);
+error_kfree:
+ kfree(ie);
+error:
+ d_fnend(3, dev, "(%p, %u) = %d\n", wusbhc, port_idx, result);
+ return;
+}
+
+static void wusb_cap_descr_printf(const unsigned level, struct device *dev,
+ const struct usb_wireless_cap_descriptor *wcd)
+{
+ d_printf(level, dev,
+ "WUSB Capability Descriptor\n"
+ " bDevCapabilityType 0x%02x\n"
+ " bmAttributes 0x%02x\n"
+ " wPhyRates 0x%04x\n"
+ " bmTFITXPowerInfo 0x%02x\n"
+ " bmFFITXPowerInfo 0x%02x\n"
+ " bmBandGroup 0x%04x\n"
+ " bReserved 0x%02x\n",
+ wcd->bDevCapabilityType,
+ wcd->bmAttributes,
+ le16_to_cpu(wcd->wPHYRates),
+ wcd->bmTFITXPowerInfo,
+ wcd->bmFFITXPowerInfo,
+ wcd->bmBandGroup,
+ wcd->bReserved);
+}
+
+/*
+ * Walk over the BOS descriptor, verify and grok it
+ *
+ * @usb_dev: referenced
+ * @wusb_dev: referenced and unlocked
+ *
+ * The BOS descriptor is defined at WUSB1.0[7.4.1], and it defines a
+ * "flexible" way to wrap all kinds of descriptors inside an standard
+ * descriptor (wonder why they didn't use normal descriptors,
+ * btw). Not like they lack code.
+ *
+ * At the end we go to look for the WUSB Device Capabilities
+ * (WUSB1.0[7.4.1.1]) that is wrapped in a device capability descriptor
+ * that is part of the BOS descriptor set. That tells us what does the
+ * device support (dual role, beacon type, UWB PHY rates).
+ */
+static int wusb_dev_bos_grok(struct usb_device *usb_dev,
+ struct wusb_dev *wusb_dev,
+ struct usb_bos_descriptor *bos, size_t desc_size)
+{
+ ssize_t result;
+ struct device *dev = &usb_dev->dev;
+ void *itr, *top;
+
+ /* Walk over BOS capabilities, verify them */
+ itr = (void *)bos + sizeof(*bos);
+ top = itr + desc_size - sizeof(*bos);
+ while (itr < top) {
+ struct usb_dev_cap_header *cap_hdr = itr;
+ size_t cap_size;
+ u8 cap_type;
+ if (top - itr < sizeof(*cap_hdr)) {
+ dev_err(dev, "Device BUG? premature end of BOS header "
+ "data [offset 0x%02x]: only %zu bytes left\n",
+ (int)(itr - (void *)bos), top - itr);
+ result = -ENOSPC;
+ goto error_bad_cap;
+ }
+ cap_size = cap_hdr->bLength;
+ cap_type = cap_hdr->bDevCapabilityType;
+ d_printf(4, dev, "BOS Capability: 0x%02x (%zu bytes)\n",
+ cap_type, cap_size);
+ if (cap_size == 0)
+ break;
+ if (cap_size > top - itr) {
+ dev_err(dev, "Device BUG? premature end of BOS data "
+ "[offset 0x%02x cap %02x %zu bytes]: "
+ "only %zu bytes left\n",
+ (int)(itr - (void *)bos),
+ cap_type, cap_size, top - itr);
+ result = -EBADF;
+ goto error_bad_cap;
+ }
+ d_dump(3, dev, itr, cap_size);
+ switch (cap_type) {
+ case USB_CAP_TYPE_WIRELESS_USB:
+ if (cap_size != sizeof(*wusb_dev->wusb_cap_descr))
+ dev_err(dev, "Device BUG? WUSB Capability "
+ "descriptor is %zu bytes vs %zu "
+ "needed\n", cap_size,
+ sizeof(*wusb_dev->wusb_cap_descr));
+ else {
+ wusb_dev->wusb_cap_descr = itr;
+ wusb_cap_descr_printf(3, dev, itr);
+ }
+ break;
+ default:
+ dev_err(dev, "BUG? Unknown BOS capability 0x%02x "
+ "(%zu bytes) at offset 0x%02x\n", cap_type,
+ cap_size, (int)(itr - (void *)bos));
+ }
+ itr += cap_size;
+ }
+ result = 0;
+error_bad_cap:
+ return result;
+}
+
+/*
+ * Add information from the BOS descriptors to the device
+ *
+ * @usb_dev: referenced
+ * @wusb_dev: referenced and unlocked
+ *
+ * So what we do is we alloc a space for the BOS descriptor of 64
+ * bytes; read the first four bytes which include the wTotalLength
+ * field (WUSB1.0[T7-26]) and if it fits in those 64 bytes, read the
+ * whole thing. If not we realloc to that size.
+ *
+ * Then we call the groking function, that will fill up
+ * wusb_dev->wusb_cap_descr, which is what we'll need later on.
+ */
+static int wusb_dev_bos_add(struct usb_device *usb_dev,
+ struct wusb_dev *wusb_dev)
+{
+ ssize_t result;
+ struct device *dev = &usb_dev->dev;
+ struct usb_bos_descriptor *bos;
+ size_t alloc_size = 32, desc_size = 4;
+
+ bos = kmalloc(alloc_size, GFP_KERNEL);
+ if (bos == NULL)
+ return -ENOMEM;
+ result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
+ if (result < 4) {
+ dev_err(dev, "Can't get BOS descriptor or too short: %zd\n",
+ result);
+ goto error_get_descriptor;
+ }
+ desc_size = le16_to_cpu(bos->wTotalLength);
+ if (desc_size >= alloc_size) {
+ kfree(bos);
+ alloc_size = desc_size;
+ bos = kmalloc(alloc_size, GFP_KERNEL);
+ if (bos == NULL)
+ return -ENOMEM;
+ }
+ result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
+ if (result < 0 || result != desc_size) {
+ dev_err(dev, "Can't get BOS descriptor or too short (need "
+ "%zu bytes): %zd\n", desc_size, result);
+ goto error_get_descriptor;
+ }
+ if (result < sizeof(*bos)
+ || le16_to_cpu(bos->wTotalLength) != desc_size) {
+ dev_err(dev, "Can't get BOS descriptor or too short (need "
+ "%zu bytes): %zd\n", desc_size, result);
+ goto error_get_descriptor;
+ }
+ d_printf(2, dev, "Got BOS descriptor %zd bytes, %u capabilities\n",
+ result, bos->bNumDeviceCaps);
+ d_dump(2, dev, bos, result);
+ result = wusb_dev_bos_grok(usb_dev, wusb_dev, bos, result);
+ if (result < 0)
+ goto error_bad_bos;
+ wusb_dev->bos = bos;
+ return 0;
+
+error_bad_bos:
+error_get_descriptor:
+ kfree(bos);
+ wusb_dev->wusb_cap_descr = NULL;
+ return result;
+}
+
+static void wusb_dev_bos_rm(struct wusb_dev *wusb_dev)
+{
+ kfree(wusb_dev->bos);
+ wusb_dev->wusb_cap_descr = NULL;
+};
+
+static struct usb_wireless_cap_descriptor wusb_cap_descr_default = {
+ .bLength = sizeof(wusb_cap_descr_default),
+ .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
+ .bDevCapabilityType = USB_CAP_TYPE_WIRELESS_USB,
+
+ .bmAttributes = USB_WIRELESS_BEACON_NONE,
+ .wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53),
+ .bmTFITXPowerInfo = 0,
+ .bmFFITXPowerInfo = 0,
+ .bmBandGroup = cpu_to_le16(0x0001), /* WUSB1.0[7.4.1] bottom */
+ .bReserved = 0
+};
+
+/*
+ * USB stack's device addition Notifier Callback
+ *
+ * Called from drivers/usb/core/hub.c when a new device is added; we
+ * use this hook to perform certain WUSB specific setup work on the
+ * new device. As well, it is the first time we can connect the
+ * wusb_dev and the usb_dev. So we note it down in wusb_dev and take a
+ * reference that we'll drop.
+ *
+ * First we need to determine if the device is a WUSB device (else we
+ * ignore it). For that we use the speed setting (USB_SPEED_VARIABLE)
+ * [FIXME: maybe we'd need something more definitive]. If so, we track
+ * it's usb_busd and from there, the WUSB HC.
+ *
+ * Because all WUSB HCs are contained in a 'struct wusbhc', voila, we
+ * get the wusbhc for the device.
+ *
+ * We have a reference on @usb_dev (as we are called at the end of its
+ * enumeration).
+ *
+ * NOTE: @usb_dev locked
+ */
+static void wusb_dev_add_ncb(struct usb_device *usb_dev)
+{
+ int result = 0;
+ struct wusb_dev *wusb_dev;
+ struct wusbhc *wusbhc;
+ struct device *dev = &usb_dev->dev;
+ u8 port_idx;
+
+ if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
+ return; /* skip non wusb and wusb RHs */
+
+ d_fnstart(3, dev, "(usb_dev %p)\n", usb_dev);
+
+ wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+ if (wusbhc == NULL)
+ goto error_nodev;
+ mutex_lock(&wusbhc->mutex);
+ wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
+ port_idx = wusb_port_no_to_idx(usb_dev->portnum);
+ mutex_unlock(&wusbhc->mutex);
+ if (wusb_dev == NULL)
+ goto error_nodev;
+ wusb_dev->usb_dev = usb_get_dev(usb_dev);
+ usb_dev->wusb_dev = wusb_dev_get(wusb_dev);
+ result = wusb_dev_sec_add(wusbhc, usb_dev, wusb_dev);
+ if (result < 0) {
+ dev_err(dev, "Cannot enable security: %d\n", result);
+ goto error_sec_add;
+ }
+ /* Now query the device for it's BOS and attach it to wusb_dev */
+ result = wusb_dev_bos_add(usb_dev, wusb_dev);
+ if (result < 0) {
+ dev_err(dev, "Cannot get BOS descriptors: %d\n", result);
+ goto error_bos_add;
+ }
+ result = wusb_dev_sysfs_add(wusbhc, usb_dev, wusb_dev);
+ if (result < 0)
+ goto error_add_sysfs;
+out:
+ wusb_dev_put(wusb_dev);
+ wusbhc_put(wusbhc);
+error_nodev:
+ d_fnend(3, dev, "(usb_dev %p) = void\n", usb_dev);
+ return;
+
+ wusb_dev_sysfs_rm(wusb_dev);
+error_add_sysfs:
+ wusb_dev_bos_rm(wusb_dev);
+error_bos_add:
+ wusb_dev_sec_rm(wusb_dev);
+error_sec_add:
+ mutex_lock(&wusbhc->mutex);
+ __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
+ mutex_unlock(&wusbhc->mutex);
+ goto out;
+}
+
+/*
+ * Undo all the steps done at connection by the notifier callback
+ *
+ * NOTE: @usb_dev locked
+ */
+static void wusb_dev_rm_ncb(struct usb_device *usb_dev)
+{
+ struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
+
+ if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
+ return; /* skip non wusb and wusb RHs */
+
+ wusb_dev_sysfs_rm(wusb_dev);
+ wusb_dev_bos_rm(wusb_dev);
+ wusb_dev_sec_rm(wusb_dev);
+ wusb_dev->usb_dev = NULL;
+ usb_dev->wusb_dev = NULL;
+ wusb_dev_put(wusb_dev);
+ usb_put_dev(usb_dev);
+}
+
+/*
+ * Handle notifications from the USB stack (notifier call back)
+ *
+ * This is called when the USB stack does a
+ * usb_{bus,device}_{add,remove}() so we can do WUSB specific
+ * handling. It is called with [for the case of
+ * USB_DEVICE_{ADD,REMOVE} with the usb_dev locked.
+ */
+int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
+ void *priv)
+{
+ int result = NOTIFY_OK;
+
+ switch (val) {
+ case USB_DEVICE_ADD:
+ wusb_dev_add_ncb(priv);
+ break;
+ case USB_DEVICE_REMOVE:
+ wusb_dev_rm_ncb(priv);
+ break;
+ case USB_BUS_ADD:
+ /* ignore (for now) */
+ case USB_BUS_REMOVE:
+ break;
+ default:
+ WARN_ON(1);
+ result = NOTIFY_BAD;
+ };
+ return result;
+}
+
+/*
+ * Return a referenced wusb_dev given a @wusbhc and @usb_dev
+ */
+struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *wusbhc,
+ struct usb_device *usb_dev)
+{
+ struct wusb_dev *wusb_dev;
+ u8 port_idx;
+
+ port_idx = wusb_port_no_to_idx(usb_dev->portnum);
+ BUG_ON(port_idx > wusbhc->ports_max);
+ wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
+ if (wusb_dev != NULL) /* ops, device is gone */
+ wusb_dev_get(wusb_dev);
+ return wusb_dev;
+}
+EXPORT_SYMBOL_GPL(__wusb_dev_get_by_usb_dev);
+
+void wusb_dev_destroy(struct kref *_wusb_dev)
+{
+ struct wusb_dev *wusb_dev
+ = container_of(_wusb_dev, struct wusb_dev, refcnt);
+ list_del_init(&wusb_dev->cack_node);
+ wusb_dev_free(wusb_dev);
+ d_fnend(1, NULL, "%s (wusb_dev %p) = void\n", __func__, wusb_dev);
+}
+EXPORT_SYMBOL_GPL(wusb_dev_destroy);
+
+/*
+ * Create all the device connect handling infrastructure
+ *
+ * This is basically the device info array, Connect Acknowledgement
+ * (cack) lists, keep-alive timers (and delayed work thread).
+ */
+int wusbhc_devconnect_create(struct wusbhc *wusbhc)
+{
+ d_fnstart(3, wusbhc->dev, "(wusbhc %p)\n", wusbhc);
+
+ wusbhc->keep_alive_ie.hdr.bIEIdentifier = WUIE_ID_KEEP_ALIVE;
+ wusbhc->keep_alive_ie.hdr.bLength = sizeof(wusbhc->keep_alive_ie.hdr);
+ INIT_DELAYED_WORK(&wusbhc->keep_alive_timer, wusbhc_keep_alive_run);
+
+ wusbhc->cack_ie.hdr.bIEIdentifier = WUIE_ID_CONNECTACK;
+ wusbhc->cack_ie.hdr.bLength = sizeof(wusbhc->cack_ie.hdr);
+ INIT_LIST_HEAD(&wusbhc->cack_list);
+
+ d_fnend(3, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc);
+ return 0;
+}
+
+/*
+ * Release all resources taken by the devconnect stuff
+ */
+void wusbhc_devconnect_destroy(struct wusbhc *wusbhc)
+{
+ d_fnstart(3, wusbhc->dev, "(wusbhc %p)\n", wusbhc);
+ d_fnend(3, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc);
+}
+
+/*
+ * wusbhc_devconnect_start - start accepting device connections
+ * @wusbhc: the WUSB HC
+ *
+ * Sets the Host Info IE to accept all new connections.
+ *
+ * FIXME: This also enables the keep alives but this is not necessary
+ * until there are connected and authenticated devices.
+ */
+int wusbhc_devconnect_start(struct wusbhc *wusbhc,
+ const struct wusb_ckhdid *chid)
+{
+ struct device *dev = wusbhc->dev;
+ struct wuie_host_info *hi;
+ int result;
+
+ hi = kzalloc(sizeof(*hi), GFP_KERNEL);
+ if (hi == NULL)
+ return -ENOMEM;
+
+ hi->hdr.bLength = sizeof(*hi);
+ hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO;
+ hi->attributes = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL);
+ hi->CHID = *chid;
+ result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr);
+ if (result < 0) {
+ dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result);
+ goto error_mmcie_set;
+ }
+ wusbhc->wuie_host_info = hi;
+
+ queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
+ (wusbhc->trust_timeout*CONFIG_HZ)/1000/2);
+
+ return 0;
+
+error_mmcie_set:
+ kfree(hi);
+ return result;
+}
+
+/*
+ * wusbhc_devconnect_stop - stop managing connected devices
+ * @wusbhc: the WUSB HC
+ *
+ * Removes the Host Info IE and stops the keep alives.
+ *
+ * FIXME: should this disconnect all devices?
+ */
+void wusbhc_devconnect_stop(struct wusbhc *wusbhc)
+{
+ cancel_delayed_work_sync(&wusbhc->keep_alive_timer);
+ WARN_ON(!list_empty(&wusbhc->cack_list));
+
+ wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr);
+ kfree(wusbhc->wuie_host_info);
+ wusbhc->wuie_host_info = NULL;
+}
+
+/*
+ * wusb_set_dev_addr - set the WUSB device address used by the host
+ * @wusbhc: the WUSB HC the device is connect to
+ * @wusb_dev: the WUSB device
+ * @addr: new device address
+ */
+int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, u8 addr)
+{
+ int result;
+
+ wusb_dev->addr = addr;
+ result = wusbhc->dev_info_set(wusbhc, wusb_dev);
+ if (result < 0)
+ dev_err(wusbhc->dev, "device %d: failed to set device "
+ "address\n", wusb_dev->port_idx);
+ else
+ dev_info(wusbhc->dev, "device %d: %s addr %u\n",
+ wusb_dev->port_idx,
+ (addr & WUSB_DEV_ADDR_UNAUTH) ? "unauth" : "auth",
+ wusb_dev->addr);
+
+ return result;
+}
diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c
new file mode 100644
index 00000000000..cfa77a01ceb
--- /dev/null
+++ b/drivers/usb/wusbcore/mmc.c
@@ -0,0 +1,321 @@
+/*
+ * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
+ * MMC (Microscheduled Management Command) handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * WUIEs and MMC IEs...well, they are almost the same at the end. MMC
+ * IEs are Wireless USB IEs that go into the MMC period...[what is
+ * that? look in Design-overview.txt].
+ *
+ *
+ * This is a simple subsystem to keep track of which IEs are being
+ * sent by the host in the MMC period.
+ *
+ * For each WUIE we ask to send, we keep it in an array, so we can
+ * request its removal later, or replace the content. They are tracked
+ * by pointer, so be sure to use the same pointer if you want to
+ * remove it or update the contents.
+ *
+ * FIXME:
+ * - add timers that autoremove intervalled IEs?
+ */
+#include <linux/usb/wusb.h>
+#include "wusbhc.h"
+
+/* Initialize the MMCIEs handling mechanism */
+int wusbhc_mmcie_create(struct wusbhc *wusbhc)
+{
+ u8 mmcies = wusbhc->mmcies_max;
+ wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL);
+ if (wusbhc->mmcie == NULL)
+ return -ENOMEM;
+ mutex_init(&wusbhc->mmcie_mutex);
+ return 0;
+}
+
+/* Release resources used by the MMCIEs handling mechanism */
+void wusbhc_mmcie_destroy(struct wusbhc *wusbhc)
+{
+ kfree(wusbhc->mmcie);
+}
+
+/*
+ * Add or replace an MMC Wireless USB IE.
+ *
+ * @interval: See WUSB1.0[8.5.3.1]
+ * @repeat_cnt: See WUSB1.0[8.5.3.1]
+ * @handle: See WUSB1.0[8.5.3.1]
+ * @wuie: Pointer to the header of the WUSB IE data to add.
+ * MUST BE allocated in a kmalloc buffer (no stack or
+ * vmalloc).
+ * THE CALLER ALWAYS OWNS THE POINTER (we don't free it
+ * on remove, we just forget about it).
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * Goes over the *whole* @wusbhc->mmcie array looking for (a) the
+ * first free spot and (b) if @wuie is already in the array (aka:
+ * transmitted in the MMCs) the spot were it is.
+ *
+ * If present, we "overwrite it" (update).
+ *
+ *
+ * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38.
+ * The host uses the handle as the 'sort' index. We
+ * allocate the last one always for the WUIE_ID_HOST_INFO, and
+ * the rest, first come first serve in inverse order.
+ *
+ * Host software must make sure that it adds the other IEs in
+ * the right order... the host hardware is responsible for
+ * placing the WCTA IEs in the right place with the other IEs
+ * set by host software.
+ *
+ * NOTE: we can access wusbhc->wa_descr without locking because it is
+ * read only.
+ */
+int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+ struct wuie_hdr *wuie)
+{
+ int result = -ENOBUFS;
+ unsigned handle, itr;
+
+ /* Search a handle, taking into account the ordering */
+ mutex_lock(&wusbhc->mmcie_mutex);
+ switch (wuie->bIEIdentifier) {
+ case WUIE_ID_HOST_INFO:
+ /* Always last */
+ handle = wusbhc->mmcies_max - 1;
+ break;
+ case WUIE_ID_ISOCH_DISCARD:
+ dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x "
+ "unimplemented\n", wuie->bIEIdentifier);
+ result = -ENOSYS;
+ goto error_unlock;
+ default:
+ /* search for it or find the last empty slot */
+ handle = ~0;
+ for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) {
+ if (wusbhc->mmcie[itr] == wuie) {
+ handle = itr;
+ break;
+ }
+ if (wusbhc->mmcie[itr] == NULL)
+ handle = itr;
+ }
+ if (handle == ~0)
+ goto error_unlock;
+ }
+ result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle,
+ wuie);
+ if (result >= 0)
+ wusbhc->mmcie[handle] = wuie;
+error_unlock:
+ mutex_unlock(&wusbhc->mmcie_mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_mmcie_set);
+
+/*
+ * Remove an MMC IE previously added with wusbhc_mmcie_set()
+ *
+ * @wuie Pointer used to add the WUIE
+ */
+void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie)
+{
+ int result;
+ unsigned handle, itr;
+
+ mutex_lock(&wusbhc->mmcie_mutex);
+ for (itr = 0; itr < wusbhc->mmcies_max; itr++) {
+ if (wusbhc->mmcie[itr] == wuie) {
+ handle = itr;
+ goto found;
+ }
+ }
+ mutex_unlock(&wusbhc->mmcie_mutex);
+ return;
+
+found:
+ result = (wusbhc->mmcie_rm)(wusbhc, handle);
+ if (result == 0)
+ wusbhc->mmcie[itr] = NULL;
+ mutex_unlock(&wusbhc->mmcie_mutex);
+}
+EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm);
+
+/*
+ * wusbhc_start - start transmitting MMCs and accepting connections
+ * @wusbhc: the HC to start
+ * @chid: the CHID to use for this host
+ *
+ * Establishes a cluster reservation, enables device connections, and
+ * starts MMCs with appropriate DNTS parameters.
+ */
+int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
+{
+ int result;
+ struct device *dev = wusbhc->dev;
+
+ WARN_ON(wusbhc->wuie_host_info != NULL);
+
+ result = wusbhc_rsv_establish(wusbhc);
+ if (result < 0) {
+ dev_err(dev, "cannot establish cluster reservation: %d\n",
+ result);
+ goto error_rsv_establish;
+ }
+
+ result = wusbhc_devconnect_start(wusbhc, chid);
+ if (result < 0) {
+ dev_err(dev, "error enabling device connections: %d\n", result);
+ goto error_devconnect_start;
+ }
+
+ result = wusbhc_sec_start(wusbhc);
+ if (result < 0) {
+ dev_err(dev, "error starting security in the HC: %d\n", result);
+ goto error_sec_start;
+ }
+ /* FIXME: the choice of the DNTS parameters is somewhat
+ * arbitrary */
+ result = wusbhc->set_num_dnts(wusbhc, 0, 15);
+ if (result < 0) {
+ dev_err(dev, "Cannot set DNTS parameters: %d\n", result);
+ goto error_set_num_dnts;
+ }
+ result = wusbhc->start(wusbhc);
+ if (result < 0) {
+ dev_err(dev, "error starting wusbch: %d\n", result);
+ goto error_wusbhc_start;
+ }
+ wusbhc->active = 1;
+ return 0;
+
+error_wusbhc_start:
+ wusbhc_sec_stop(wusbhc);
+error_set_num_dnts:
+error_sec_start:
+ wusbhc_devconnect_stop(wusbhc);
+error_devconnect_start:
+ wusbhc_rsv_terminate(wusbhc);
+error_rsv_establish:
+ return result;
+}
+
+/*
+ * Disconnect all from the WUSB Channel
+ *
+ * Send a Host Disconnect IE in the MMC, wait, don't send it any more
+ */
+static int __wusbhc_host_disconnect_ie(struct wusbhc *wusbhc)
+{
+ int result = -ENOMEM;
+ struct wuie_host_disconnect *host_disconnect_ie;
+ might_sleep();
+ host_disconnect_ie = kmalloc(sizeof(*host_disconnect_ie), GFP_KERNEL);
+ if (host_disconnect_ie == NULL)
+ goto error_alloc;
+ host_disconnect_ie->hdr.bLength = sizeof(*host_disconnect_ie);
+ host_disconnect_ie->hdr.bIEIdentifier = WUIE_ID_HOST_DISCONNECT;
+ result = wusbhc_mmcie_set(wusbhc, 0, 0, &host_disconnect_ie->hdr);
+ if (result < 0)
+ goto error_mmcie_set;
+
+ /* WUSB1.0[8.5.3.1 & 7.5.2] */
+ msleep(100);
+ wusbhc_mmcie_rm(wusbhc, &host_disconnect_ie->hdr);
+error_mmcie_set:
+ kfree(host_disconnect_ie);
+error_alloc:
+ return result;
+}
+
+/*
+ * wusbhc_stop - stop transmitting MMCs
+ * @wusbhc: the HC to stop
+ *
+ * Send a Host Disconnect IE, wait, remove all the MMCs (stop sending MMCs).
+ *
+ * If we can't allocate a Host Stop IE, screw it, we don't notify the
+ * devices we are disconnecting...
+ */
+void wusbhc_stop(struct wusbhc *wusbhc)
+{
+ if (wusbhc->active) {
+ wusbhc->active = 0;
+ wusbhc->stop(wusbhc);
+ wusbhc_sec_stop(wusbhc);
+ __wusbhc_host_disconnect_ie(wusbhc);
+ wusbhc_devconnect_stop(wusbhc);
+ wusbhc_rsv_terminate(wusbhc);
+ }
+}
+EXPORT_SYMBOL_GPL(wusbhc_stop);
+
+/*
+ * Change the CHID in a WUSB Channel
+ *
+ * If it is just a new CHID, send a Host Disconnect IE and then change
+ * the CHID IE.
+ */
+static int __wusbhc_chid_change(struct wusbhc *wusbhc,
+ const struct wusb_ckhdid *chid)
+{
+ int result = -ENOSYS;
+ struct device *dev = wusbhc->dev;
+ dev_err(dev, "%s() not implemented yet\n", __func__);
+ return result;
+
+ BUG_ON(wusbhc->wuie_host_info == NULL);
+ __wusbhc_host_disconnect_ie(wusbhc);
+ wusbhc->wuie_host_info->CHID = *chid;
+ result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->wuie_host_info->hdr);
+ if (result < 0)
+ dev_err(dev, "Can't update Host Info WUSB IE: %d\n", result);
+ return result;
+}
+
+/*
+ * Set/reset/update a new CHID
+ *
+ * Depending on the previous state of the MMCs, start, stop or change
+ * the sent MMC. This effectively switches the host controller on and
+ * off (radio wise).
+ */
+int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
+{
+ int result = 0;
+
+ if (memcmp(chid, &wusb_ckhdid_zero, sizeof(chid)) == 0)
+ chid = NULL;
+
+ mutex_lock(&wusbhc->mutex);
+ if (wusbhc->active) {
+ if (chid)
+ result = __wusbhc_chid_change(wusbhc, chid);
+ else
+ wusbhc_stop(wusbhc);
+ } else {
+ if (chid)
+ wusbhc_start(wusbhc, chid);
+ }
+ mutex_unlock(&wusbhc->mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_chid_set);
diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c
new file mode 100644
index 00000000000..7cc51e9905c
--- /dev/null
+++ b/drivers/usb/wusbcore/pal.c
@@ -0,0 +1,42 @@
+/*
+ * Wireless USB Host Controller
+ * UWB Protocol Adaptation Layer (PAL) glue.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "wusbhc.h"
+
+/**
+ * wusbhc_pal_register - register the WUSB HC as a UWB PAL
+ * @wusbhc: the WUSB HC
+ */
+int wusbhc_pal_register(struct wusbhc *wusbhc)
+{
+ uwb_pal_init(&wusbhc->pal);
+
+ wusbhc->pal.name = "wusbhc";
+ wusbhc->pal.device = wusbhc->usb_hcd.self.controller;
+
+ return uwb_pal_register(wusbhc->uwb_rc, &wusbhc->pal);
+}
+
+/**
+ * wusbhc_pal_register - unregister the WUSB HC as a UWB PAL
+ * @wusbhc: the WUSB HC
+ */
+void wusbhc_pal_unregister(struct wusbhc *wusbhc)
+{
+ uwb_pal_unregister(wusbhc->uwb_rc, &wusbhc->pal);
+}
diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c
new file mode 100644
index 00000000000..fc63e77ded2
--- /dev/null
+++ b/drivers/usb/wusbcore/reservation.c
@@ -0,0 +1,115 @@
+/*
+ * WUSB cluster reservation management
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/uwb.h>
+
+#include "wusbhc.h"
+
+/*
+ * WUSB cluster reservations are multicast reservations with the
+ * broadcast cluster ID (BCID) as the target DevAddr.
+ *
+ * FIXME: consider adjusting the reservation depending on what devices
+ * are attached.
+ */
+
+static int wusbhc_bwa_set(struct wusbhc *wusbhc, u8 stream,
+ const struct uwb_mas_bm *mas)
+{
+ if (mas == NULL)
+ mas = &uwb_mas_bm_zero;
+ return wusbhc->bwa_set(wusbhc, stream, mas);
+}
+
+/**
+ * wusbhc_rsv_complete_cb - WUSB HC reservation complete callback
+ * @rsv: the reservation
+ *
+ * Either set or clear the HC's view of the reservation.
+ *
+ * FIXME: when a reservation is denied the HC should be stopped.
+ */
+static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv)
+{
+ struct wusbhc *wusbhc = rsv->pal_priv;
+ struct device *dev = wusbhc->dev;
+ char buf[72];
+
+ switch (rsv->state) {
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS);
+ dev_dbg(dev, "established reservation: %s\n", buf);
+ wusbhc_bwa_set(wusbhc, rsv->stream, &rsv->mas);
+ break;
+ case UWB_RSV_STATE_NONE:
+ dev_dbg(dev, "removed reservation\n");
+ wusbhc_bwa_set(wusbhc, 0, NULL);
+ wusbhc->rsv = NULL;
+ break;
+ default:
+ dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state);
+ break;
+ }
+}
+
+
+/**
+ * wusbhc_rsv_establish - establish a reservation for the cluster
+ * @wusbhc: the WUSB HC requesting a bandwith reservation
+ */
+int wusbhc_rsv_establish(struct wusbhc *wusbhc)
+{
+ struct uwb_rc *rc = wusbhc->uwb_rc;
+ struct uwb_rsv *rsv;
+ struct uwb_dev_addr bcid;
+ int ret;
+
+ rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc);
+ if (rsv == NULL)
+ return -ENOMEM;
+
+ bcid.data[0] = wusbhc->cluster_id;
+ bcid.data[1] = 0;
+
+ rsv->owner = &rc->uwb_dev;
+ rsv->target.type = UWB_RSV_TARGET_DEVADDR;
+ rsv->target.devaddr = bcid;
+ rsv->type = UWB_DRP_TYPE_PRIVATE;
+ rsv->max_mas = 256;
+ rsv->min_mas = 16; /* one MAS per zone? */
+ rsv->sparsity = 16; /* at least one MAS in each zone? */
+ rsv->is_multicast = true;
+
+ ret = uwb_rsv_establish(rsv);
+ if (ret == 0)
+ wusbhc->rsv = rsv;
+ else
+ uwb_rsv_destroy(rsv);
+ return ret;
+}
+
+
+/**
+ * wusbhc_rsv_terminate - terminate any cluster reservation
+ * @wusbhc: the WUSB host whose reservation is to be terminated
+ */
+void wusbhc_rsv_terminate(struct wusbhc *wusbhc)
+{
+ if (wusbhc->rsv)
+ uwb_rsv_terminate(wusbhc->rsv);
+}
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c
new file mode 100644
index 00000000000..267a6432510
--- /dev/null
+++ b/drivers/usb/wusbcore/rh.c
@@ -0,0 +1,477 @@
+/*
+ * Wireless USB Host Controller
+ * Root Hub operations
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * We fake a root hub that has fake ports (as many as simultaneous
+ * devices the Wireless USB Host Controller can deal with). For each
+ * port we keep an state in @wusbhc->port[index] identical to the one
+ * specified in the USB2.0[ch11] spec and some extra device
+ * information that complements the one in 'struct usb_device' (as
+ * this lacs a hcpriv pointer).
+ *
+ * Note this is common to WHCI and HWA host controllers.
+ *
+ * Through here we enable most of the state changes that the USB stack
+ * will use to connect or disconnect devices. We need to do some
+ * forced adaptation of Wireless USB device states vs. wired:
+ *
+ * USB: WUSB:
+ *
+ * Port Powered-off port slot n/a
+ * Powered-on port slot available
+ * Disconnected port slot available
+ * Connected port slot assigned device
+ * device sent DN_Connect
+ * device was authenticated
+ * Enabled device is authenticated, transitioned
+ * from unauth -> auth -> default address
+ * -> enabled
+ * Reset disconnect
+ * Disable disconnect
+ *
+ * This maps the standard USB port states with the WUSB device states
+ * so we can fake ports without having to modify the USB stack.
+ *
+ * FIXME: this process will change in the future
+ *
+ *
+ * ENTRY POINTS
+ *
+ * Our entry points into here are, as in hcd.c, the USB stack root hub
+ * ops defined in the usb_hcd struct:
+ *
+ * wusbhc_rh_status_data() Provide hub and port status data bitmap
+ *
+ * wusbhc_rh_control() Execution of all the major requests
+ * you can do to a hub (Set|Clear
+ * features, get descriptors, status, etc).
+ *
+ * wusbhc_rh_[suspend|resume]() That
+ *
+ * wusbhc_rh_start_port_reset() ??? unimplemented
+ */
+#include "wusbhc.h"
+
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+/*
+ * Reset a fake port
+ *
+ * This can be called to reset a port from any other state or to reset
+ * it when connecting. In Wireless USB they are different; when doing
+ * a new connect that involves going over the authentication. When
+ * just reseting, its a different story.
+ *
+ * The Linux USB stack resets a port twice before it considers it
+ * enabled, so we have to detect and ignore that.
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * Supposedly we are the only thread accesing @wusbhc->port; in any
+ * case, maybe we should move the mutex locking from
+ * wusbhc_devconnect_auth() to here.
+ *
+ * @port_idx refers to the wusbhc's port index, not the USB port number
+ */
+static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx)
+{
+ int result = 0;
+ struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx);
+
+ d_fnstart(3, wusbhc->dev, "(wusbhc %p port_idx %u)\n",
+ wusbhc, port_idx);
+ if (port->reset_count == 0) {
+ wusbhc_devconnect_auth(wusbhc, port_idx);
+ port->reset_count++;
+ } else if (port->reset_count == 1)
+ /* see header */
+ d_printf(2, wusbhc->dev, "Ignoring second reset on port_idx "
+ "%u\n", port_idx);
+ else
+ result = wusbhc_dev_reset(wusbhc, port_idx);
+ d_fnend(3, wusbhc->dev, "(wusbhc %p port_idx %u) = %d\n",
+ wusbhc, port_idx, result);
+ return result;
+}
+
+/*
+ * Return the hub change status bitmap
+ *
+ * The bits in the change status bitmap are cleared when a
+ * ClearPortFeature request is issued (USB2.0[11.12.3,11.12.4].
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * WARNING!! This gets called from atomic context; we cannot get the
+ * mutex--the only race condition we can find is some bit
+ * changing just after we copy it, which shouldn't be too
+ * big of a problem [and we can't make it an spinlock
+ * because other parts need to take it and sleep] .
+ *
+ * @usb_hcd is refcounted, so it won't dissapear under us
+ * and before killing a host, the polling of the root hub
+ * would be stopped anyway.
+ */
+int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ size_t cnt, size;
+ unsigned long *buf = (unsigned long *) _buf;
+
+ d_fnstart(1, wusbhc->dev, "(wusbhc %p)\n", wusbhc);
+ /* WE DON'T LOCK, see comment */
+ size = wusbhc->ports_max + 1 /* hub bit */;
+ size = (size + 8 - 1) / 8; /* round to bytes */
+ for (cnt = 0; cnt < wusbhc->ports_max; cnt++)
+ if (wusb_port_by_idx(wusbhc, cnt)->change)
+ set_bit(cnt + 1, buf);
+ else
+ clear_bit(cnt + 1, buf);
+ d_fnend(1, wusbhc->dev, "(wusbhc %p) %u, buffer:\n", wusbhc, (int)size);
+ d_dump(1, wusbhc->dev, _buf, size);
+ return size;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
+
+/*
+ * Return the hub's desciptor
+ *
+ * NOTE: almost cut and paste from ehci-hub.c
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked
+ */
+static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue,
+ u16 wIndex,
+ struct usb_hub_descriptor *descr,
+ u16 wLength)
+{
+ u16 temp = 1 + (wusbhc->ports_max / 8);
+ u8 length = 7 + 2 * temp;
+
+ if (wLength < length)
+ return -ENOSPC;
+ descr->bDescLength = 7 + 2 * temp;
+ descr->bDescriptorType = 0x29; /* HUB type */
+ descr->bNbrPorts = wusbhc->ports_max;
+ descr->wHubCharacteristics = cpu_to_le16(
+ 0x00 /* All ports power at once */
+ | 0x00 /* not part of compound device */
+ | 0x10 /* No overcurrent protection */
+ | 0x00 /* 8 FS think time FIXME ?? */
+ | 0x00); /* No port indicators */
+ descr->bPwrOn2PwrGood = 0;
+ descr->bHubContrCurrent = 0;
+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+ memset(&descr->bitmap[0], 0, temp);
+ memset(&descr->bitmap[temp], 0xff, temp);
+ return 0;
+}
+
+/*
+ * Clear a hub feature
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * Nothing to do, so no locking needed ;)
+ */
+static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature)
+{
+ int result;
+ struct device *dev = wusbhc->dev;
+
+ d_fnstart(4, dev, "(%p, feature 0x%04u)\n", wusbhc, feature);
+ switch (feature) {
+ case C_HUB_LOCAL_POWER:
+ /* FIXME: maybe plug bit 0 to the power input status,
+ * if any?
+ * see wusbhc_rh_get_hub_status() */
+ case C_HUB_OVER_CURRENT:
+ result = 0;
+ break;
+ default:
+ result = -EPIPE;
+ }
+ d_fnend(4, dev, "(%p, feature 0x%04u), %d\n", wusbhc, feature, result);
+ return result;
+}
+
+/*
+ * Return hub status (it is always zero...)
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * Nothing to do, so no locking needed ;)
+ */
+static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf,
+ u16 wLength)
+{
+ /* FIXME: maybe plug bit 0 to the power input status (if any)? */
+ *buf = 0;
+ return 0;
+}
+
+/*
+ * Set a port feature
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature,
+ u8 selector, u8 port_idx)
+{
+ int result = -EINVAL;
+ struct device *dev = wusbhc->dev;
+
+ d_fnstart(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d)\n",
+ feature, selector, port_idx);
+
+ if (port_idx > wusbhc->ports_max)
+ goto error;
+
+ switch (feature) {
+ /* According to USB2.0[11.24.2.13]p2, these features
+ * are not required to be implemented. */
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ case USB_PORT_FEAT_C_ENABLE:
+ case USB_PORT_FEAT_C_SUSPEND:
+ case USB_PORT_FEAT_C_CONNECTION:
+ case USB_PORT_FEAT_C_RESET:
+ result = 0;
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ /* No such thing, but we fake it works */
+ mutex_lock(&wusbhc->mutex);
+ wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER;
+ mutex_unlock(&wusbhc->mutex);
+ result = 0;
+ break;
+ case USB_PORT_FEAT_RESET:
+ result = wusbhc_rh_port_reset(wusbhc, port_idx);
+ break;
+ case USB_PORT_FEAT_ENABLE:
+ case USB_PORT_FEAT_SUSPEND:
+ dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n",
+ port_idx, feature, selector);
+ result = -ENOSYS;
+ break;
+ default:
+ dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n",
+ port_idx, feature, selector);
+ result = -EPIPE;
+ break;
+ }
+error:
+ d_fnend(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d) = %d\n",
+ feature, selector, port_idx, result);
+ return result;
+}
+
+/*
+ * Clear a port feature...
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
+ u8 selector, u8 port_idx)
+{
+ int result = -EINVAL;
+ struct device *dev = wusbhc->dev;
+
+ d_fnstart(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d)\n",
+ wusbhc, feature, selector, port_idx);
+
+ if (port_idx > wusbhc->ports_max)
+ goto error;
+
+ mutex_lock(&wusbhc->mutex);
+ result = 0;
+ switch (feature) {
+ case USB_PORT_FEAT_POWER: /* fake port always on */
+ /* According to USB2.0[11.24.2.7.1.4], no need to implement? */
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET;
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION;
+ break;
+ case USB_PORT_FEAT_ENABLE:
+ __wusbhc_dev_disable(wusbhc, port_idx);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE;
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ case USB_PORT_FEAT_C_SUSPEND:
+ case 0xffff: /* ??? FIXME */
+ dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n",
+ port_idx, feature, selector);
+ /* dump_stack(); */
+ result = -ENOSYS;
+ break;
+ default:
+ dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n",
+ port_idx, feature, selector);
+ result = -EPIPE;
+ break;
+ }
+ mutex_unlock(&wusbhc->mutex);
+error:
+ d_fnend(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d) = "
+ "%d\n", wusbhc, feature, selector, port_idx, result);
+ return result;
+}
+
+/*
+ * Return the port's status
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx,
+ u32 *_buf, u16 wLength)
+{
+ int result = -EINVAL;
+ u16 *buf = (u16 *) _buf;
+
+ d_fnstart(1, wusbhc->dev, "(wusbhc %p port_idx %u wLength %u)\n",
+ wusbhc, port_idx, wLength);
+ if (port_idx > wusbhc->ports_max)
+ goto error;
+ mutex_lock(&wusbhc->mutex);
+ buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status);
+ buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change);
+ result = 0;
+ mutex_unlock(&wusbhc->mutex);
+error:
+ d_fnend(1, wusbhc->dev, "(wusbhc %p) = %d, buffer:\n", wusbhc, result);
+ d_dump(1, wusbhc->dev, _buf, wLength);
+ return result;
+}
+
+/*
+ * Entry point for Root Hub operations
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ int result = -ENOSYS;
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+
+ switch (reqntype) {
+ case GetHubDescriptor:
+ result = wusbhc_rh_get_hub_descr(
+ wusbhc, wValue, wIndex,
+ (struct usb_hub_descriptor *) buf, wLength);
+ break;
+ case ClearHubFeature:
+ result = wusbhc_rh_clear_hub_feat(wusbhc, wValue);
+ break;
+ case GetHubStatus:
+ result = wusbhc_rh_get_hub_status(wusbhc, (u32 *)buf, wLength);
+ break;
+
+ case SetPortFeature:
+ result = wusbhc_rh_set_port_feat(wusbhc, wValue, wIndex >> 8,
+ (wIndex & 0xff) - 1);
+ break;
+ case ClearPortFeature:
+ result = wusbhc_rh_clear_port_feat(wusbhc, wValue, wIndex >> 8,
+ (wIndex & 0xff) - 1);
+ break;
+ case GetPortStatus:
+ result = wusbhc_rh_get_port_status(wusbhc, wIndex - 1,
+ (u32 *)buf, wLength);
+ break;
+
+ case SetHubFeature:
+ default:
+ dev_err(wusbhc->dev, "%s (%p [%p], %x, %x, %x, %p, %x) "
+ "UNIMPLEMENTED\n", __func__, usb_hcd, wusbhc, reqntype,
+ wValue, wIndex, buf, wLength);
+ /* dump_stack(); */
+ result = -ENOSYS;
+ }
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_control);
+
+int wusbhc_rh_suspend(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
+ usb_hcd, wusbhc);
+ /* dump_stack(); */
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_suspend);
+
+int wusbhc_rh_resume(struct usb_hcd *usb_hcd)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
+ usb_hcd, wusbhc);
+ /* dump_stack(); */
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_resume);
+
+int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx)
+{
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ dev_err(wusbhc->dev, "%s (%p [%p], port_idx %u) UNIMPLEMENTED\n",
+ __func__, usb_hcd, wusbhc, port_idx);
+ WARN_ON(1);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_start_port_reset);
+
+static void wusb_port_init(struct wusb_port *port)
+{
+ port->status |= USB_PORT_STAT_HIGH_SPEED;
+}
+
+/*
+ * Alloc fake port specific fields and status.
+ */
+int wusbhc_rh_create(struct wusbhc *wusbhc)
+{
+ int result = -ENOMEM;
+ size_t port_size, itr;
+ port_size = wusbhc->ports_max * sizeof(wusbhc->port[0]);
+ wusbhc->port = kzalloc(port_size, GFP_KERNEL);
+ if (wusbhc->port == NULL)
+ goto error_port_alloc;
+ for (itr = 0; itr < wusbhc->ports_max; itr++)
+ wusb_port_init(&wusbhc->port[itr]);
+ result = 0;
+error_port_alloc:
+ return result;
+}
+
+void wusbhc_rh_destroy(struct wusbhc *wusbhc)
+{
+ kfree(wusbhc->port);
+}
diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c
new file mode 100644
index 00000000000..a101cad6a8d
--- /dev/null
+++ b/drivers/usb/wusbcore/security.c
@@ -0,0 +1,642 @@
+/*
+ * Wireless USB Host Controller
+ * Security support: encryption enablement, etc
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ */
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/random.h>
+#include "wusbhc.h"
+
+/*
+ * DEBUG & SECURITY WARNING!!!!
+ *
+ * If you enable this past 1, the debug code will weaken the
+ * cryptographic safety of the system (on purpose, for debugging).
+ *
+ * Weaken means:
+ * we print secret keys and intermediate values all the way,
+ */
+#undef D_LOCAL
+#define D_LOCAL 2
+#include <linux/uwb/debug.h>
+
+static void wusbhc_set_gtk_callback(struct urb *urb);
+static void wusbhc_gtk_rekey_done_work(struct work_struct *work);
+
+int wusbhc_sec_create(struct wusbhc *wusbhc)
+{
+ wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) + sizeof(wusbhc->gtk.data);
+ wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY;
+ wusbhc->gtk.descr.bReserved = 0;
+
+ wusbhc->gtk_index = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK,
+ WUSB_KEY_INDEX_ORIGINATOR_HOST);
+
+ INIT_WORK(&wusbhc->gtk_rekey_done_work, wusbhc_gtk_rekey_done_work);
+
+ return 0;
+}
+
+
+/* Called when the HC is destroyed */
+void wusbhc_sec_destroy(struct wusbhc *wusbhc)
+{
+}
+
+
+/**
+ * wusbhc_next_tkid - generate a new, currently unused, TKID
+ * @wusbhc: the WUSB host controller
+ * @wusb_dev: the device whose PTK the TKID is for
+ * (or NULL for a TKID for a GTK)
+ *
+ * The generated TKID consist of two parts: the device's authenicated
+ * address (or 0 or a GTK); and an incrementing number. This ensures
+ * that TKIDs cannot be shared between devices and by the time the
+ * incrementing number wraps around the older TKIDs will no longer be
+ * in use (a maximum of two keys may be active at any one time).
+ */
+static u32 wusbhc_next_tkid(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ u32 *tkid;
+ u32 addr;
+
+ if (wusb_dev == NULL) {
+ tkid = &wusbhc->gtk_tkid;
+ addr = 0;
+ } else {
+ tkid = &wusb_port_by_idx(wusbhc, wusb_dev->port_idx)->ptk_tkid;
+ addr = wusb_dev->addr & 0x7f;
+ }
+
+ *tkid = (addr << 8) | ((*tkid + 1) & 0xff);
+
+ return *tkid;
+}
+
+static void wusbhc_generate_gtk(struct wusbhc *wusbhc)
+{
+ const size_t key_size = sizeof(wusbhc->gtk.data);
+ u32 tkid;
+
+ tkid = wusbhc_next_tkid(wusbhc, NULL);
+
+ wusbhc->gtk.descr.tTKID[0] = (tkid >> 0) & 0xff;
+ wusbhc->gtk.descr.tTKID[1] = (tkid >> 8) & 0xff;
+ wusbhc->gtk.descr.tTKID[2] = (tkid >> 16) & 0xff;
+
+ get_random_bytes(wusbhc->gtk.descr.bKeyData, key_size);
+}
+
+/**
+ * wusbhc_sec_start - start the security management process
+ * @wusbhc: the WUSB host controller
+ *
+ * Generate and set an initial GTK on the host controller.
+ *
+ * Called when the HC is started.
+ */
+int wusbhc_sec_start(struct wusbhc *wusbhc)
+{
+ const size_t key_size = sizeof(wusbhc->gtk.data);
+ int result;
+
+ wusbhc_generate_gtk(wusbhc);
+
+ result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
+ &wusbhc->gtk.descr.bKeyData, key_size);
+ if (result < 0)
+ dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n",
+ result);
+
+ return result;
+}
+
+/**
+ * wusbhc_sec_stop - stop the security management process
+ * @wusbhc: the WUSB host controller
+ *
+ * Wait for any pending GTK rekeys to stop.
+ */
+void wusbhc_sec_stop(struct wusbhc *wusbhc)
+{
+ cancel_work_sync(&wusbhc->gtk_rekey_done_work);
+}
+
+
+/** @returns encryption type name */
+const char *wusb_et_name(u8 x)
+{
+ switch (x) {
+ case USB_ENC_TYPE_UNSECURE: return "unsecure";
+ case USB_ENC_TYPE_WIRED: return "wired";
+ case USB_ENC_TYPE_CCM_1: return "CCM-1";
+ case USB_ENC_TYPE_RSA_1: return "RSA-1";
+ default: return "unknown";
+ }
+}
+EXPORT_SYMBOL_GPL(wusb_et_name);
+
+/*
+ * Set the device encryption method
+ *
+ * We tell the device which encryption method to use; we do this when
+ * setting up the device's security.
+ */
+static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value)
+{
+ int result;
+ struct device *dev = &usb_dev->dev;
+ struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
+
+ if (value) {
+ value = wusb_dev->ccm1_etd.bEncryptionValue;
+ } else {
+ /* FIXME: should be wusb_dev->etd[UNSECURE].bEncryptionValue */
+ value = 0;
+ }
+ /* Set device's */
+ result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_ENCRYPTION,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ value, 0, NULL, 0, 1000 /* FIXME: arbitrary */);
+ if (result < 0)
+ dev_err(dev, "Can't set device's WUSB encryption to "
+ "%s (value %d): %d\n",
+ wusb_et_name(wusb_dev->ccm1_etd.bEncryptionType),
+ wusb_dev->ccm1_etd.bEncryptionValue, result);
+ return result;
+}
+
+/*
+ * Set the GTK to be used by a device.
+ *
+ * The device must be authenticated.
+ */
+static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+ struct usb_device *usb_dev = wusb_dev->usb_dev;
+
+ return usb_control_msg(
+ usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_DESCRIPTOR,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ USB_DT_KEY << 8 | wusbhc->gtk_index, 0,
+ &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
+ 1000);
+}
+
+
+/* FIXME: prototype for adding security */
+int wusb_dev_sec_add(struct wusbhc *wusbhc,
+ struct usb_device *usb_dev, struct wusb_dev *wusb_dev)
+{
+ int result, bytes, secd_size;
+ struct device *dev = &usb_dev->dev;
+ struct usb_security_descriptor secd;
+ const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
+ void *secd_buf;
+ const void *itr, *top;
+ char buf[64];
+
+ d_fnstart(3, dev, "(usb_dev %p, wusb_dev %p)\n", usb_dev, wusb_dev);
+ result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
+ 0, &secd, sizeof(secd));
+ if (result < sizeof(secd)) {
+ dev_err(dev, "Can't read security descriptor or "
+ "not enough data: %d\n", result);
+ goto error_secd;
+ }
+ secd_size = le16_to_cpu(secd.wTotalLength);
+ d_printf(5, dev, "got %d bytes of sec descriptor, total is %d\n",
+ result, secd_size);
+ secd_buf = kmalloc(secd_size, GFP_KERNEL);
+ if (secd_buf == NULL) {
+ dev_err(dev, "Can't allocate space for security descriptors\n");
+ goto error_secd_alloc;
+ }
+ result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
+ 0, secd_buf, secd_size);
+ if (result < secd_size) {
+ dev_err(dev, "Can't read security descriptor or "
+ "not enough data: %d\n", result);
+ goto error_secd_all;
+ }
+ d_printf(5, dev, "got %d bytes of sec descriptors\n", result);
+ bytes = 0;
+ itr = secd_buf + sizeof(secd);
+ top = secd_buf + result;
+ while (itr < top) {
+ etd = itr;
+ if (top - itr < sizeof(*etd)) {
+ dev_err(dev, "BUG: bad device security descriptor; "
+ "not enough data (%zu vs %zu bytes left)\n",
+ top - itr, sizeof(*etd));
+ break;
+ }
+ if (etd->bLength < sizeof(*etd)) {
+ dev_err(dev, "BUG: bad device encryption descriptor; "
+ "descriptor is too short "
+ "(%u vs %zu needed)\n",
+ etd->bLength, sizeof(*etd));
+ break;
+ }
+ itr += etd->bLength;
+ bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
+ "%s (0x%02x/%02x) ",
+ wusb_et_name(etd->bEncryptionType),
+ etd->bEncryptionValue, etd->bAuthKeyIndex);
+ if (etd->bEncryptionType == USB_ENC_TYPE_CCM_1)
+ ccm1_etd = etd;
+ }
+ /* This code only supports CCM1 as of now. */
+ /* FIXME: user has to choose which sec mode to use?
+ * In theory we want CCM */
+ if (ccm1_etd == NULL) {
+ dev_err(dev, "WUSB device doesn't support CCM1 encryption, "
+ "can't use!\n");
+ result = -EINVAL;
+ goto error_no_ccm1;
+ }
+ wusb_dev->ccm1_etd = *ccm1_etd;
+ dev_info(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n",
+ buf, wusb_et_name(ccm1_etd->bEncryptionType),
+ ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex);
+ result = 0;
+ kfree(secd_buf);
+out:
+ d_fnend(3, dev, "(usb_dev %p, wusb_dev %p) = %d\n",
+ usb_dev, wusb_dev, result);
+ return result;
+
+
+error_no_ccm1:
+error_secd_all:
+ kfree(secd_buf);
+error_secd_alloc:
+error_secd:
+ goto out;
+}
+
+void wusb_dev_sec_rm(struct wusb_dev *wusb_dev)
+{
+ /* Nothing so far */
+}
+
+static void hs_printk(unsigned level, struct device *dev,
+ struct usb_handshake *hs)
+{
+ d_printf(level, dev,
+ " bMessageNumber: %u\n"
+ " bStatus: %u\n"
+ " tTKID: %02x %02x %02x\n"
+ " CDID: %02x %02x %02x %02x %02x %02x %02x %02x\n"
+ " %02x %02x %02x %02x %02x %02x %02x %02x\n"
+ " nonce: %02x %02x %02x %02x %02x %02x %02x %02x\n"
+ " %02x %02x %02x %02x %02x %02x %02x %02x\n"
+ " MIC: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ hs->bMessageNumber, hs->bStatus,
+ hs->tTKID[2], hs->tTKID[1], hs->tTKID[0],
+ hs->CDID[0], hs->CDID[1], hs->CDID[2], hs->CDID[3],
+ hs->CDID[4], hs->CDID[5], hs->CDID[6], hs->CDID[7],
+ hs->CDID[8], hs->CDID[9], hs->CDID[10], hs->CDID[11],
+ hs->CDID[12], hs->CDID[13], hs->CDID[14], hs->CDID[15],
+ hs->nonce[0], hs->nonce[1], hs->nonce[2], hs->nonce[3],
+ hs->nonce[4], hs->nonce[5], hs->nonce[6], hs->nonce[7],
+ hs->nonce[8], hs->nonce[9], hs->nonce[10], hs->nonce[11],
+ hs->nonce[12], hs->nonce[13], hs->nonce[14], hs->nonce[15],
+ hs->MIC[0], hs->MIC[1], hs->MIC[2], hs->MIC[3],
+ hs->MIC[4], hs->MIC[5], hs->MIC[6], hs->MIC[7]);
+}
+
+/**
+ * Update the address of an unauthenticated WUSB device
+ *
+ * Once we have successfully authenticated, we take it to addr0 state
+ * and then to a normal address.
+ *
+ * Before the device's address (as known by it) was usb_dev->devnum |
+ * 0x80 (unauthenticated address). With this we update it to usb_dev->devnum.
+ */
+static int wusb_dev_update_address(struct wusbhc *wusbhc,
+ struct wusb_dev *wusb_dev)
+{
+ int result = -ENOMEM;
+ struct usb_device *usb_dev = wusb_dev->usb_dev;
+ struct device *dev = &usb_dev->dev;
+ u8 new_address = wusb_dev->addr & 0x7F;
+
+ /* Set address 0 */
+ result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_ADDRESS, 0,
+ 0, 0, NULL, 0, 1000 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "auth failed: can't set address 0: %d\n",
+ result);
+ goto error_addr0;
+ }
+ result = wusb_set_dev_addr(wusbhc, wusb_dev, 0);
+ if (result < 0)
+ goto error_addr0;
+ usb_ep0_reinit(usb_dev);
+
+ /* Set new (authenticated) address. */
+ result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_ADDRESS, 0,
+ new_address, 0, NULL, 0,
+ 1000 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "auth failed: can't set address %u: %d\n",
+ new_address, result);
+ goto error_addr;
+ }
+ result = wusb_set_dev_addr(wusbhc, wusb_dev, new_address);
+ if (result < 0)
+ goto error_addr;
+ usb_ep0_reinit(usb_dev);
+ usb_dev->authenticated = 1;
+error_addr:
+error_addr0:
+ return result;
+}
+
+/*
+ *
+ *
+ */
+/* FIXME: split and cleanup */
+int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
+ struct wusb_ckhdid *ck)
+{
+ int result = -ENOMEM;
+ struct usb_device *usb_dev = wusb_dev->usb_dev;
+ struct device *dev = &usb_dev->dev;
+ u32 tkid;
+ __le32 tkid_le;
+ struct usb_handshake *hs;
+ struct aes_ccm_nonce ccm_n;
+ u8 mic[8];
+ struct wusb_keydvt_in keydvt_in;
+ struct wusb_keydvt_out keydvt_out;
+
+ hs = kzalloc(3*sizeof(hs[0]), GFP_KERNEL);
+ if (hs == NULL) {
+ dev_err(dev, "can't allocate handshake data\n");
+ goto error_kzalloc;
+ }
+
+ /* We need to turn encryption before beginning the 4way
+ * hshake (WUSB1.0[.3.2.2]) */
+ result = wusb_dev_set_encryption(usb_dev, 1);
+ if (result < 0)
+ goto error_dev_set_encryption;
+
+ tkid = wusbhc_next_tkid(wusbhc, wusb_dev);
+ tkid_le = cpu_to_le32(tkid);
+
+ hs[0].bMessageNumber = 1;
+ hs[0].bStatus = 0;
+ memcpy(hs[0].tTKID, &tkid_le, sizeof(hs[0].tTKID));
+ hs[0].bReserved = 0;
+ memcpy(hs[0].CDID, &wusb_dev->cdid, sizeof(hs[0].CDID));
+ get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce));
+ memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */
+
+ d_printf(1, dev, "I: sending hs1:\n");
+ hs_printk(2, dev, &hs[0]);
+
+ result = usb_control_msg(
+ usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_HANDSHAKE,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 1, 0, &hs[0], sizeof(hs[0]), 1000 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "Handshake1: request failed: %d\n", result);
+ goto error_hs1;
+ }
+
+ /* Handshake 2, from the device -- need to verify fields */
+ result = usb_control_msg(
+ usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_GET_HANDSHAKE,
+ USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 2, 0, &hs[1], sizeof(hs[1]), 1000 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "Handshake2: request failed: %d\n", result);
+ goto error_hs2;
+ }
+ d_printf(1, dev, "got HS2:\n");
+ hs_printk(2, dev, &hs[1]);
+
+ result = -EINVAL;
+ if (hs[1].bMessageNumber != 2) {
+ dev_err(dev, "Handshake2 failed: bad message number %u\n",
+ hs[1].bMessageNumber);
+ goto error_hs2;
+ }
+ if (hs[1].bStatus != 0) {
+ dev_err(dev, "Handshake2 failed: bad status %u\n",
+ hs[1].bStatus);
+ goto error_hs2;
+ }
+ if (memcmp(hs[0].tTKID, hs[1].tTKID, sizeof(hs[0].tTKID))) {
+ dev_err(dev, "Handshake2 failed: TKID mismatch "
+ "(#1 0x%02x%02x%02x vs #2 0x%02x%02x%02x)\n",
+ hs[0].tTKID[0], hs[0].tTKID[1], hs[0].tTKID[2],
+ hs[1].tTKID[0], hs[1].tTKID[1], hs[1].tTKID[2]);
+ goto error_hs2;
+ }
+ if (memcmp(hs[0].CDID, hs[1].CDID, sizeof(hs[0].CDID))) {
+ dev_err(dev, "Handshake2 failed: CDID mismatch\n");
+ goto error_hs2;
+ }
+
+ /* Setup the CCM nonce */
+ memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn)); /* Per WUSB1.0[6.5.2] */
+ memcpy(ccm_n.tkid, &tkid_le, sizeof(ccm_n.tkid));
+ ccm_n.src_addr = wusbhc->uwb_rc->uwb_dev.dev_addr;
+ ccm_n.dest_addr.data[0] = wusb_dev->addr;
+ ccm_n.dest_addr.data[1] = 0;
+
+ /* Derive the KCK and PTK from CK, the CCM, H and D nonces */
+ memcpy(keydvt_in.hnonce, hs[0].nonce, sizeof(keydvt_in.hnonce));
+ memcpy(keydvt_in.dnonce, hs[1].nonce, sizeof(keydvt_in.dnonce));
+ result = wusb_key_derive(&keydvt_out, ck->data, &ccm_n, &keydvt_in);
+ if (result < 0) {
+ dev_err(dev, "Handshake2 failed: cannot derive keys: %d\n",
+ result);
+ goto error_hs2;
+ }
+ d_printf(2, dev, "KCK:\n");
+ d_dump(2, dev, keydvt_out.kck, sizeof(keydvt_out.kck));
+ d_printf(2, dev, "PTK:\n");
+ d_dump(2, dev, keydvt_out.ptk, sizeof(keydvt_out.ptk));
+
+ /* Compute MIC and verify it */
+ result = wusb_oob_mic(mic, keydvt_out.kck, &ccm_n, &hs[1]);
+ if (result < 0) {
+ dev_err(dev, "Handshake2 failed: cannot compute MIC: %d\n",
+ result);
+ goto error_hs2;
+ }
+
+ d_printf(2, dev, "MIC:\n");
+ d_dump(2, dev, mic, sizeof(mic));
+ if (memcmp(hs[1].MIC, mic, sizeof(hs[1].MIC))) {
+ dev_err(dev, "Handshake2 failed: MIC mismatch\n");
+ goto error_hs2;
+ }
+
+ /* Send Handshake3 */
+ hs[2].bMessageNumber = 3;
+ hs[2].bStatus = 0;
+ memcpy(hs[2].tTKID, &tkid_le, sizeof(hs[2].tTKID));
+ hs[2].bReserved = 0;
+ memcpy(hs[2].CDID, &wusb_dev->cdid, sizeof(hs[2].CDID));
+ memcpy(hs[2].nonce, hs[0].nonce, sizeof(hs[2].nonce));
+ result = wusb_oob_mic(hs[2].MIC, keydvt_out.kck, &ccm_n, &hs[2]);
+ if (result < 0) {
+ dev_err(dev, "Handshake3 failed: cannot compute MIC: %d\n",
+ result);
+ goto error_hs2;
+ }
+
+ d_printf(1, dev, "I: sending hs3:\n");
+ hs_printk(2, dev, &hs[2]);
+
+ result = usb_control_msg(
+ usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_HANDSHAKE,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 3, 0, &hs[2], sizeof(hs[2]), 1000 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "Handshake3: request failed: %d\n", result);
+ goto error_hs3;
+ }
+
+ d_printf(1, dev, "I: turning on encryption on host for device\n");
+ d_dump(2, dev, keydvt_out.ptk, sizeof(keydvt_out.ptk));
+ result = wusbhc->set_ptk(wusbhc, wusb_dev->port_idx, tkid,
+ keydvt_out.ptk, sizeof(keydvt_out.ptk));
+ if (result < 0)
+ goto error_wusbhc_set_ptk;
+
+ d_printf(1, dev, "I: setting a GTK\n");
+ result = wusb_dev_set_gtk(wusbhc, wusb_dev);
+ if (result < 0) {
+ dev_err(dev, "Set GTK for device: request failed: %d\n",
+ result);
+ goto error_wusbhc_set_gtk;
+ }
+
+ /* Update the device's address from unauth to auth */
+ if (usb_dev->authenticated == 0) {
+ d_printf(1, dev, "I: updating addres to auth from non-auth\n");
+ result = wusb_dev_update_address(wusbhc, wusb_dev);
+ if (result < 0)
+ goto error_dev_update_address;
+ }
+ result = 0;
+ d_printf(1, dev, "I: 4way handshke done, device authenticated\n");
+
+error_dev_update_address:
+error_wusbhc_set_gtk:
+error_wusbhc_set_ptk:
+error_hs3:
+error_hs2:
+error_hs1:
+ memset(hs, 0, 3*sizeof(hs[0]));
+ memset(&keydvt_out, 0, sizeof(keydvt_out));
+ memset(&keydvt_in, 0, sizeof(keydvt_in));
+ memset(&ccm_n, 0, sizeof(ccm_n));
+ memset(mic, 0, sizeof(mic));
+ if (result < 0) {
+ /* error path */
+ wusb_dev_set_encryption(usb_dev, 0);
+ }
+error_dev_set_encryption:
+ kfree(hs);
+error_kzalloc:
+ return result;
+}
+
+/*
+ * Once all connected and authenticated devices have received the new
+ * GTK, switch the host to using it.
+ */
+static void wusbhc_gtk_rekey_done_work(struct work_struct *work)
+{
+ struct wusbhc *wusbhc = container_of(work, struct wusbhc, gtk_rekey_done_work);
+ size_t key_size = sizeof(wusbhc->gtk.data);
+
+ mutex_lock(&wusbhc->mutex);
+
+ if (--wusbhc->pending_set_gtks == 0)
+ wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size);
+
+ mutex_unlock(&wusbhc->mutex);
+}
+
+static void wusbhc_set_gtk_callback(struct urb *urb)
+{
+ struct wusbhc *wusbhc = urb->context;
+
+ queue_work(wusbd, &wusbhc->gtk_rekey_done_work);
+}
+
+/**
+ * wusbhc_gtk_rekey - generate and distribute a new GTK
+ * @wusbhc: the WUSB host controller
+ *
+ * Generate a new GTK and distribute it to all connected and
+ * authenticated devices. When all devices have the new GTK, the host
+ * starts using it.
+ *
+ * This must be called after every device disconnect (see [WUSB]
+ * section 6.2.11.2).
+ */
+void wusbhc_gtk_rekey(struct wusbhc *wusbhc)
+{
+ static const size_t key_size = sizeof(wusbhc->gtk.data);
+ int p;
+
+ wusbhc_generate_gtk(wusbhc);
+
+ for (p = 0; p < wusbhc->ports_max; p++) {
+ struct wusb_dev *wusb_dev;
+
+ wusb_dev = wusbhc->port[p].wusb_dev;
+ if (!wusb_dev || !wusb_dev->usb_dev | !wusb_dev->usb_dev->authenticated)
+ continue;
+
+ usb_fill_control_urb(wusb_dev->set_gtk_urb, wusb_dev->usb_dev,
+ usb_sndctrlpipe(wusb_dev->usb_dev, 0),
+ (void *)wusb_dev->set_gtk_req,
+ &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
+ wusbhc_set_gtk_callback, wusbhc);
+ if (usb_submit_urb(wusb_dev->set_gtk_urb, GFP_KERNEL) == 0)
+ wusbhc->pending_set_gtks++;
+ }
+ if (wusbhc->pending_set_gtks == 0)
+ wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size);
+}
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c
new file mode 100644
index 00000000000..9d04722415b
--- /dev/null
+++ b/drivers/usb/wusbcore/wa-hc.c
@@ -0,0 +1,95 @@
+/*
+ * Wire Adapter Host Controller Driver
+ * Common items to HWA and DWA based HCDs
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ */
+#include "wusbhc.h"
+#include "wa-hc.h"
+
+/**
+ * Assumes
+ *
+ * wa->usb_dev and wa->usb_iface initialized and refcounted,
+ * wa->wa_descr initialized.
+ */
+int wa_create(struct wahc *wa, struct usb_interface *iface)
+{
+ int result;
+ struct device *dev = &iface->dev;
+
+ result = wa_rpipes_create(wa);
+ if (result < 0)
+ goto error_rpipes_create;
+ /* Fill up Data Transfer EP pointers */
+ wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc;
+ wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
+ wa->xfer_result_size = le16_to_cpu(wa->dti_epd->wMaxPacketSize);
+ wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL);
+ if (wa->xfer_result == NULL)
+ goto error_xfer_result_alloc;
+ result = wa_nep_create(wa, iface);
+ if (result < 0) {
+ dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n",
+ result);
+ goto error_nep_create;
+ }
+ return 0;
+
+error_nep_create:
+ kfree(wa->xfer_result);
+error_xfer_result_alloc:
+ wa_rpipes_destroy(wa);
+error_rpipes_create:
+ return result;
+}
+EXPORT_SYMBOL_GPL(wa_create);
+
+
+void __wa_destroy(struct wahc *wa)
+{
+ if (wa->dti_urb) {
+ usb_kill_urb(wa->dti_urb);
+ usb_put_urb(wa->dti_urb);
+ usb_kill_urb(wa->buf_in_urb);
+ usb_put_urb(wa->buf_in_urb);
+ }
+ kfree(wa->xfer_result);
+ wa_nep_destroy(wa);
+ wa_rpipes_destroy(wa);
+}
+EXPORT_SYMBOL_GPL(__wa_destroy);
+
+/**
+ * wa_reset_all - reset the WA device
+ * @wa: the WA to be reset
+ *
+ * For HWAs the radio controller and all other PALs are also reset.
+ */
+void wa_reset_all(struct wahc *wa)
+{
+ /* FIXME: assuming HWA. */
+ wusbhc_reset_all(wa->wusb);
+}
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless USB Wire Adapter core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h
new file mode 100644
index 00000000000..586d350cdb4
--- /dev/null
+++ b/drivers/usb/wusbcore/wa-hc.h
@@ -0,0 +1,417 @@
+/*
+ * HWA Host Controller Driver
+ * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8])
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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 driver implements a USB Host Controller (struct usb_hcd) for a
+ * Wireless USB Host Controller based on the Wireless USB 1.0
+ * Host-Wire-Adapter specification (in layman terms, a USB-dongle that
+ * implements a Wireless USB host).
+ *
+ * Check out the Design-overview.txt file in the source documentation
+ * for other details on the implementation.
+ *
+ * Main blocks:
+ *
+ * driver glue with the driver API, workqueue daemon
+ *
+ * lc RC instance life cycle management (create, destroy...)
+ *
+ * hcd glue with the USB API Host Controller Interface API.
+ *
+ * nep Notification EndPoint managent: collect notifications
+ * and queue them with the workqueue daemon.
+ *
+ * Handle notifications as coming from the NEP. Sends them
+ * off others to their respective modules (eg: connect,
+ * disconnect and reset go to devconnect).
+ *
+ * rpipe Remote Pipe management; rpipe is what we use to write
+ * to an endpoint on a WUSB device that is connected to a
+ * HWA RC.
+ *
+ * xfer Transfer managment -- this is all the code that gets a
+ * buffer and pushes it to a device (or viceversa). *
+ *
+ * Some day a lot of this code will be shared between this driver and
+ * the drivers for DWA (xfer, rpipe).
+ *
+ * All starts at driver.c:hwahc_probe(), when one of this guys is
+ * connected. hwahc_disconnect() stops it.
+ *
+ * During operation, the main driver is devices connecting or
+ * disconnecting. They cause the HWA RC to send notifications into
+ * nep.c:hwahc_nep_cb() that will dispatch them to
+ * notif.c:wa_notif_dispatch(). From there they will fan to cause
+ * device connects, disconnects, etc.
+ *
+ * Note much of the activity is difficult to follow. For example a
+ * device connect goes to devconnect, which will cause the "fake" root
+ * hub port to show a connect and stop there. Then khubd will notice
+ * and call into the rh.c:hwahc_rc_port_reset() code to authenticate
+ * the device (and this might require user intervention) and enable
+ * the port.
+ *
+ * We also have a timer workqueue going from devconnect.c that
+ * schedules in hwahc_devconnect_create().
+ *
+ * The rest of the traffic is in the usual entry points of a USB HCD,
+ * which are hooked up in driver.c:hwahc_rc_driver, and defined in
+ * hcd.c.
+ */
+
+#ifndef __HWAHC_INTERNAL_H__
+#define __HWAHC_INTERNAL_H__
+
+#include <linux/completion.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/uwb.h>
+#include <linux/usb/wusb.h>
+#include <linux/usb/wusb-wa.h>
+
+struct wusbhc;
+struct wahc;
+extern void wa_urb_enqueue_run(struct work_struct *ws);
+
+/**
+ * RPipe instance
+ *
+ * @descr's fields are kept in LE, as we need to send it back and
+ * forth.
+ *
+ * @wa is referenced when set
+ *
+ * @segs_available is the number of requests segments that still can
+ * be submitted to the controller without overloading
+ * it. It is initialized to descr->wRequests when
+ * aiming.
+ *
+ * A rpipe supports a max of descr->wRequests at the same time; before
+ * submitting seg_lock has to be taken. If segs_avail > 0, then we can
+ * submit; if not, we have to queue them.
+ */
+struct wa_rpipe {
+ struct kref refcnt;
+ struct usb_rpipe_descriptor descr;
+ struct usb_host_endpoint *ep;
+ struct wahc *wa;
+ spinlock_t seg_lock;
+ struct list_head seg_list;
+ atomic_t segs_available;
+ u8 buffer[1]; /* For reads/writes on USB */
+};
+
+
+/**
+ * Instance of a HWA Host Controller
+ *
+ * Except where a more specific lock/mutex applies or atomic, all
+ * fields protected by @mutex.
+ *
+ * @wa_descr Can be accessed without locking because it is in
+ * the same area where the device descriptors were
+ * read, so it is guaranteed to exist umodified while
+ * the device exists.
+ *
+ * Endianess has been converted to CPU's.
+ *
+ * @nep_* can be accessed without locking as its processing is
+ * serialized; we submit a NEP URB and it comes to
+ * hwahc_nep_cb(), which won't issue another URB until it is
+ * done processing it.
+ *
+ * @xfer_list:
+ *
+ * List of active transfers to verify existence from a xfer id
+ * gotten from the xfer result message. Can't use urb->list because
+ * it goes by endpoint, and we don't know the endpoint at the time
+ * when we get the xfer result message. We can't really rely on the
+ * pointer (will have to change for 64 bits) as the xfer id is 32 bits.
+ *
+ * @xfer_delayed_list: List of transfers that need to be started
+ * (with a workqueue, because they were
+ * submitted from an atomic context).
+ *
+ * FIXME: this needs to be layered up: a wusbhc layer (for sharing
+ * comonalities with WHCI), a wa layer (for sharing
+ * comonalities with DWA-RC).
+ */
+struct wahc {
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+
+ /* HC to deliver notifications */
+ union {
+ struct wusbhc *wusb;
+ struct dwahc *dwa;
+ };
+
+ const struct usb_endpoint_descriptor *dto_epd, *dti_epd;
+ const struct usb_wa_descriptor *wa_descr;
+
+ struct urb *nep_urb; /* Notification EndPoint [lockless] */
+ struct edc nep_edc;
+ void *nep_buffer;
+ size_t nep_buffer_size;
+
+ atomic_t notifs_queued;
+
+ u16 rpipes;
+ unsigned long *rpipe_bm; /* rpipe usage bitmap */
+ spinlock_t rpipe_bm_lock; /* protect rpipe_bm */
+ struct mutex rpipe_mutex; /* assigning resources to endpoints */
+
+ struct urb *dti_urb; /* URB for reading xfer results */
+ struct urb *buf_in_urb; /* URB for reading data in */
+ struct edc dti_edc; /* DTI error density counter */
+ struct wa_xfer_result *xfer_result; /* real size = dti_ep maxpktsize */
+ size_t xfer_result_size;
+
+ s32 status; /* For reading status */
+
+ struct list_head xfer_list;
+ struct list_head xfer_delayed_list;
+ spinlock_t xfer_list_lock;
+ struct work_struct xfer_work;
+ atomic_t xfer_id_count;
+};
+
+
+extern int wa_create(struct wahc *wa, struct usb_interface *iface);
+extern void __wa_destroy(struct wahc *wa);
+void wa_reset_all(struct wahc *wa);
+
+
+/* Miscellaneous constants */
+enum {
+ /** Max number of EPROTO errors we tolerate on the NEP in a
+ * period of time */
+ HWAHC_EPROTO_MAX = 16,
+ /** Period of time for EPROTO errors (in jiffies) */
+ HWAHC_EPROTO_PERIOD = 4 * HZ,
+};
+
+
+/* Notification endpoint handling */
+extern int wa_nep_create(struct wahc *, struct usb_interface *);
+extern void wa_nep_destroy(struct wahc *);
+
+static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask)
+{
+ struct urb *urb = wa->nep_urb;
+ urb->transfer_buffer = wa->nep_buffer;
+ urb->transfer_buffer_length = wa->nep_buffer_size;
+ return usb_submit_urb(urb, gfp_mask);
+}
+
+static inline void wa_nep_disarm(struct wahc *wa)
+{
+ usb_kill_urb(wa->nep_urb);
+}
+
+
+/* RPipes */
+static inline void wa_rpipe_init(struct wahc *wa)
+{
+ spin_lock_init(&wa->rpipe_bm_lock);
+ mutex_init(&wa->rpipe_mutex);
+}
+
+static inline void wa_init(struct wahc *wa)
+{
+ edc_init(&wa->nep_edc);
+ atomic_set(&wa->notifs_queued, 0);
+ wa_rpipe_init(wa);
+ edc_init(&wa->dti_edc);
+ INIT_LIST_HEAD(&wa->xfer_list);
+ INIT_LIST_HEAD(&wa->xfer_delayed_list);
+ spin_lock_init(&wa->xfer_list_lock);
+ INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run);
+ atomic_set(&wa->xfer_id_count, 1);
+}
+
+/**
+ * Destroy a pipe (when refcount drops to zero)
+ *
+ * Assumes it has been moved to the "QUIESCING" state.
+ */
+struct wa_xfer;
+extern void rpipe_destroy(struct kref *_rpipe);
+static inline
+void __rpipe_get(struct wa_rpipe *rpipe)
+{
+ kref_get(&rpipe->refcnt);
+}
+extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *,
+ struct urb *, gfp_t);
+static inline void rpipe_put(struct wa_rpipe *rpipe)
+{
+ kref_put(&rpipe->refcnt, rpipe_destroy);
+
+}
+extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *);
+extern int wa_rpipes_create(struct wahc *);
+extern void wa_rpipes_destroy(struct wahc *);
+static inline void rpipe_avail_dec(struct wa_rpipe *rpipe)
+{
+ atomic_dec(&rpipe->segs_available);
+}
+
+/**
+ * Returns true if the rpipe is ready to submit more segments.
+ */
+static inline int rpipe_avail_inc(struct wa_rpipe *rpipe)
+{
+ return atomic_inc_return(&rpipe->segs_available) > 0
+ && !list_empty(&rpipe->seg_list);
+}
+
+
+/* Transferring data */
+extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *,
+ struct urb *, gfp_t);
+extern int wa_urb_dequeue(struct wahc *, struct urb *);
+extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *);
+
+
+/* Misc
+ *
+ * FIXME: Refcounting for the actual @hwahc object is not correct; I
+ * mean, this should be refcounting on the HCD underneath, but
+ * it is not. In any case, the semantics for HCD refcounting
+ * are *weird*...on refcount reaching zero it just frees
+ * it...no RC specific function is called...unless I miss
+ * something.
+ *
+ * FIXME: has to go away in favour of an 'struct' hcd based sollution
+ */
+static inline struct wahc *wa_get(struct wahc *wa)
+{
+ usb_get_intf(wa->usb_iface);
+ return wa;
+}
+
+static inline void wa_put(struct wahc *wa)
+{
+ usb_put_intf(wa->usb_iface);
+}
+
+
+static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature)
+{
+ return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ feature,
+ wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, 1000 /* FIXME: arbitrary */);
+}
+
+
+static inline int __wa_set_feature(struct wahc *wa, u16 feature)
+{
+ return __wa_feature(wa, 1, feature);
+}
+
+
+static inline int __wa_clear_feature(struct wahc *wa, u16 feature)
+{
+ return __wa_feature(wa, 0, feature);
+}
+
+
+/**
+ * Return the status of a Wire Adapter
+ *
+ * @wa: Wire Adapter instance
+ * @returns < 0 errno code on error, or status bitmap as described
+ * in WUSB1.0[8.3.1.6].
+ *
+ * NOTE: need malloc, some arches don't take USB from the stack
+ */
+static inline
+s32 __wa_get_status(struct wahc *wa)
+{
+ s32 result;
+ result = usb_control_msg(
+ wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+ USB_REQ_GET_STATUS,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ &wa->status, sizeof(wa->status),
+ 1000 /* FIXME: arbitrary */);
+ if (result >= 0)
+ result = wa->status;
+ return result;
+}
+
+
+/**
+ * Waits until the Wire Adapter's status matches @mask/@value
+ *
+ * @wa: Wire Adapter instance.
+ * @returns < 0 errno code on error, otherwise status.
+ *
+ * Loop until the WAs status matches the mask and value (status & mask
+ * == value). Timeout if it doesn't happen.
+ *
+ * FIXME: is there an official specification on how long status
+ * changes can take?
+ */
+static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value)
+{
+ s32 result;
+ unsigned loops = 10;
+ do {
+ msleep(50);
+ result = __wa_get_status(wa);
+ if ((result & mask) == value)
+ break;
+ if (loops-- == 0) {
+ result = -ETIMEDOUT;
+ break;
+ }
+ } while (result >= 0);
+ return result;
+}
+
+
+/** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */
+static inline int __wa_stop(struct wahc *wa)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+
+ result = __wa_clear_feature(wa, WA_ENABLE);
+ if (result < 0 && result != -ENODEV) {
+ dev_err(dev, "error commanding HC to stop: %d\n", result);
+ goto out;
+ }
+ result = __wa_wait_status(wa, WA_ENABLE, 0);
+ if (result < 0 && result != -ENODEV)
+ dev_err(dev, "error waiting for HC to stop: %d\n", result);
+out:
+ return 0;
+}
+
+
+#endif /* #ifndef __HWAHC_INTERNAL_H__ */
diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c
new file mode 100644
index 00000000000..3f542990c73
--- /dev/null
+++ b/drivers/usb/wusbcore/wa-nep.c
@@ -0,0 +1,310 @@
+/*
+ * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
+ * Notification EndPoint support
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * 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 part takes care of getting the notification from the hw
+ * only and dispatching through wusbwad into
+ * wa_notif_dispatch. Handling is done there.
+ *
+ * WA notifications are limited in size; most of them are three or
+ * four bytes long, and the longest is the HWA Device Notification,
+ * which would not exceed 38 bytes (DNs are limited in payload to 32
+ * bytes plus 3 bytes header (WUSB1.0[7.6p2]), plus 3 bytes HWA
+ * header (WUSB1.0[8.5.4.2]).
+ *
+ * It is not clear if more than one Device Notification can be packed
+ * in a HWA Notification, I assume no because of the wording in
+ * WUSB1.0[8.5.4.2]. In any case, the bigger any notification could
+ * get is 256 bytes (as the bLength field is a byte).
+ *
+ * So what we do is we have this buffer and read into it; when a
+ * notification arrives we schedule work to a specific, single thread
+ * workqueue (so notifications are serialized) and copy the
+ * notification data. After scheduling the work, we rearm the read from
+ * the notification endpoint.
+ *
+ * Entry points here are:
+ *
+ * wa_nep_[create|destroy]() To initialize/release this subsystem
+ *
+ * wa_nep_cb() Callback for the notification
+ * endpoint; when data is ready, this
+ * does the dispatching.
+ */
+#include <linux/workqueue.h>
+#include <linux/ctype.h>
+#include <linux/uwb/debug.h>
+#include "wa-hc.h"
+#include "wusbhc.h"
+
+/* Structure for queueing notifications to the workqueue */
+struct wa_notif_work {
+ struct work_struct work;
+ struct wahc *wa;
+ size_t size;
+ u8 data[];
+};
+
+/*
+ * Process incoming notifications from the WA's Notification EndPoint
+ * [the wuswad daemon, basically]
+ *
+ * @_nw: Pointer to a descriptor which has the pointer to the
+ * @wa, the size of the buffer and the work queue
+ * structure (so we can free all when done).
+ * @returns 0 if ok, < 0 errno code on error.
+ *
+ * All notifications follow the same format; they need to start with a
+ * 'struct wa_notif_hdr' header, so it is easy to parse through
+ * them. We just break the buffer in individual notifications (the
+ * standard doesn't say if it can be done or is forbidden, so we are
+ * cautious) and dispatch each.
+ *
+ * So the handling layers are is:
+ *
+ * WA specific notification (from NEP)
+ * Device Notification Received -> wa_handle_notif_dn()
+ * WUSB Device notification generic handling
+ * BPST Adjustment -> wa_handle_notif_bpst_adj()
+ * ... -> ...
+ *
+ * @wa has to be referenced
+ */
+static void wa_notif_dispatch(struct work_struct *ws)
+{
+ void *itr;
+ u8 missing = 0;
+ struct wa_notif_work *nw = container_of(ws, struct wa_notif_work, work);
+ struct wahc *wa = nw->wa;
+ struct wa_notif_hdr *notif_hdr;
+ size_t size;
+
+ struct device *dev = &wa->usb_iface->dev;
+
+#if 0
+ /* FIXME: need to check for this??? */
+ if (usb_hcd->state == HC_STATE_QUIESCING) /* Going down? */
+ goto out; /* screw it */
+#endif
+ atomic_dec(&wa->notifs_queued); /* Throttling ctl */
+ dev = &wa->usb_iface->dev;
+ size = nw->size;
+ itr = nw->data;
+
+ while (size) {
+ if (size < sizeof(*notif_hdr)) {
+ missing = sizeof(*notif_hdr) - size;
+ goto exhausted_buffer;
+ }
+ notif_hdr = itr;
+ if (size < notif_hdr->bLength)
+ goto exhausted_buffer;
+ itr += notif_hdr->bLength;
+ size -= notif_hdr->bLength;
+ /* Dispatch the notification [don't use itr or size!] */
+ switch (notif_hdr->bNotifyType) {
+ case HWA_NOTIF_DN: {
+ struct hwa_notif_dn *hwa_dn;
+ hwa_dn = container_of(notif_hdr, struct hwa_notif_dn,
+ hdr);
+ wusbhc_handle_dn(wa->wusb, hwa_dn->bSourceDeviceAddr,
+ hwa_dn->dndata,
+ notif_hdr->bLength - sizeof(*hwa_dn));
+ break;
+ }
+ case WA_NOTIF_TRANSFER:
+ wa_handle_notif_xfer(wa, notif_hdr);
+ break;
+ case DWA_NOTIF_RWAKE:
+ case DWA_NOTIF_PORTSTATUS:
+ case HWA_NOTIF_BPST_ADJ:
+ /* FIXME: unimplemented WA NOTIFs */
+ /* fallthru */
+ default:
+ if (printk_ratelimit()) {
+ dev_err(dev, "HWA: unknown notification 0x%x, "
+ "%zu bytes; discarding\n",
+ notif_hdr->bNotifyType,
+ (size_t)notif_hdr->bLength);
+ dump_bytes(dev, notif_hdr, 16);
+ }
+ break;
+ }
+ }
+out:
+ wa_put(wa);
+ kfree(nw);
+ return;
+
+ /* THIS SHOULD NOT HAPPEN
+ *
+ * Buffer exahusted with partial data remaining; just warn and
+ * discard the data, as this should not happen.
+ */
+exhausted_buffer:
+ if (!printk_ratelimit())
+ goto out;
+ dev_warn(dev, "HWA: device sent short notification, "
+ "%d bytes missing; discarding %d bytes.\n",
+ missing, (int)size);
+ dump_bytes(dev, itr, size);
+ goto out;
+}
+
+/*
+ * Deliver incoming WA notifications to the wusbwa workqueue
+ *
+ * @wa: Pointer the Wire Adapter Controller Data Streaming
+ * instance (part of an 'struct usb_hcd').
+ * @size: Size of the received buffer
+ * @returns 0 if ok, < 0 errno code on error.
+ *
+ * The input buffer is @wa->nep_buffer, with @size bytes
+ * (guaranteed to fit in the allocated space,
+ * @wa->nep_buffer_size).
+ */
+static int wa_nep_queue(struct wahc *wa, size_t size)
+{
+ int result = 0;
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_notif_work *nw;
+
+ /* dev_fnstart(dev, "(wa %p, size %zu)\n", wa, size); */
+ BUG_ON(size > wa->nep_buffer_size);
+ if (size == 0)
+ goto out;
+ if (atomic_read(&wa->notifs_queued) > 200) {
+ if (printk_ratelimit())
+ dev_err(dev, "Too many notifications queued, "
+ "throttling back\n");
+ goto out;
+ }
+ nw = kzalloc(sizeof(*nw) + size, GFP_ATOMIC);
+ if (nw == NULL) {
+ if (printk_ratelimit())
+ dev_err(dev, "No memory to queue notification\n");
+ goto out;
+ }
+ INIT_WORK(&nw->work, wa_notif_dispatch);
+ nw->wa = wa_get(wa);
+ nw->size = size;
+ memcpy(nw->data, wa->nep_buffer, size);
+ atomic_inc(&wa->notifs_queued); /* Throttling ctl */
+ queue_work(wusbd, &nw->work);
+out:
+ /* dev_fnend(dev, "(wa %p, size %zu) = result\n", wa, size, result); */
+ return result;
+}
+
+/*
+ * Callback for the notification event endpoint
+ *
+ * Check's that everything is fine and then passes the data to be
+ * queued to the workqueue.
+ */
+static void wa_nep_cb(struct urb *urb)
+{
+ int result;
+ struct wahc *wa = urb->context;
+ struct device *dev = &wa->usb_iface->dev;
+
+ switch (result = urb->status) {
+ case 0:
+ result = wa_nep_queue(wa, urb->actual_length);
+ if (result < 0)
+ dev_err(dev, "NEP: unable to process notification(s): "
+ "%d\n", result);
+ break;
+ case -ECONNRESET: /* Not an error, but a controlled situation; */
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ case -ESHUTDOWN:
+ dev_dbg(dev, "NEP: going down %d\n", urb->status);
+ goto out;
+ default: /* On general errors, we retry unless it gets ugly */
+ if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "NEP: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ goto out;
+ }
+ dev_err(dev, "NEP: URB error %d\n", urb->status);
+ }
+ result = wa_nep_arm(wa, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "NEP: cannot submit URB: %d\n", result);
+ wa_reset_all(wa);
+ }
+out:
+ return;
+}
+
+/*
+ * Initialize @wa's notification and event's endpoint stuff
+ *
+ * This includes the allocating the read buffer, the context ID
+ * allocation bitmap, the URB and submitting the URB.
+ */
+int wa_nep_create(struct wahc *wa, struct usb_interface *iface)
+{
+ int result;
+ struct usb_endpoint_descriptor *epd;
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+ struct device *dev = &iface->dev;
+
+ edc_init(&wa->nep_edc);
+ epd = &iface->cur_altsetting->endpoint[0].desc;
+ wa->nep_buffer_size = 1024;
+ wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL);
+ if (wa->nep_buffer == NULL) {
+ dev_err(dev, "Unable to allocate notification's read buffer\n");
+ goto error_nep_buffer;
+ }
+ wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (wa->nep_urb == NULL) {
+ dev_err(dev, "Unable to allocate notification URB\n");
+ goto error_urb_alloc;
+ }
+ usb_fill_int_urb(wa->nep_urb, usb_dev,
+ usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
+ wa->nep_buffer, wa->nep_buffer_size,
+ wa_nep_cb, wa, epd->bInterval);
+ result = wa_nep_arm(wa, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "Cannot submit notification URB: %d\n", result);
+ goto error_nep_arm;
+ }
+ return 0;
+
+error_nep_arm:
+ usb_free_urb(wa->nep_urb);
+error_urb_alloc:
+ kfree(wa->nep_buffer);
+error_nep_buffer:
+ return -ENOMEM;
+}
+
+void wa_nep_destroy(struct wahc *wa)
+{
+ wa_nep_disarm(wa);
+ usb_free_urb(wa->nep_urb);
+ kfree(wa->nep_buffer);
+}
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
new file mode 100644
index 00000000000..f18e4aae66e
--- /dev/null
+++ b/drivers/usb/wusbcore/wa-rpipe.c
@@ -0,0 +1,562 @@
+/*
+ * WUSB Wire Adapter
+ * rpipe management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ *
+ * RPIPE
+ *
+ * Targetted at different downstream endpoints
+ *
+ * Descriptor: use to config the remote pipe.
+ *
+ * The number of blocks could be dynamic (wBlocks in descriptor is
+ * 0)--need to schedule them then.
+ *
+ * Each bit in wa->rpipe_bm represents if an rpipe is being used or
+ * not. Rpipes are represented with a 'struct wa_rpipe' that is
+ * attached to the hcpriv member of a 'struct usb_host_endpoint'.
+ *
+ * When you need to xfer data to an endpoint, you get an rpipe for it
+ * with wa_ep_rpipe_get(), which gives you a reference to the rpipe
+ * and keeps a single one (the first one) with the endpoint. When you
+ * are done transferring, you drop that reference. At the end the
+ * rpipe is always allocated and bound to the endpoint. There it might
+ * be recycled when not used.
+ *
+ * Addresses:
+ *
+ * We use a 1:1 mapping mechanism between port address (0 based
+ * index, actually) and the address. The USB stack knows about this.
+ *
+ * USB Stack port number 4 (1 based)
+ * WUSB code port index 3 (0 based)
+ * USB Addresss 5 (2 based -- 0 is for default, 1 for root hub)
+ *
+ * Now, because we don't use the concept as default address exactly
+ * like the (wired) USB code does, we need to kind of skip it. So we
+ * never take addresses from the urb->pipe, but from the
+ * urb->dev->devnum, to make sure that we always have the right
+ * destination address.
+ */
+#include <linux/init.h>
+#include <asm/atomic.h>
+#include <linux/bitmap.h>
+#include "wusbhc.h"
+#include "wa-hc.h"
+
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+
+static int __rpipe_get_descr(struct wahc *wa,
+ struct usb_rpipe_descriptor *descr, u16 index)
+{
+ ssize_t result;
+ struct device *dev = &wa->usb_iface->dev;
+
+ /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor()
+ * function because the arguments are different.
+ */
+ d_printf(1, dev, "rpipe %u: get descr\n", index);
+ result = usb_control_msg(
+ wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+ USB_REQ_GET_DESCRIPTOR,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
+ 1000 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "rpipe %u: get descriptor failed: %d\n",
+ index, (int)result);
+ goto error;
+ }
+ if (result < sizeof(*descr)) {
+ dev_err(dev, "rpipe %u: got short descriptor "
+ "(%zd vs %zd bytes needed)\n",
+ index, result, sizeof(*descr));
+ result = -EINVAL;
+ goto error;
+ }
+ result = 0;
+
+error:
+ return result;
+}
+
+/*
+ *
+ * The descriptor is assumed to be properly initialized (ie: you got
+ * it through __rpipe_get_descr()).
+ */
+static int __rpipe_set_descr(struct wahc *wa,
+ struct usb_rpipe_descriptor *descr, u16 index)
+{
+ ssize_t result;
+ struct device *dev = &wa->usb_iface->dev;
+
+ /* we cannot use the usb_get_descriptor() function because the
+ * arguments are different.
+ */
+ d_printf(1, dev, "rpipe %u: set descr\n", index);
+ result = usb_control_msg(
+ wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_SET_DESCRIPTOR,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
+ HZ / 10);
+ if (result < 0) {
+ dev_err(dev, "rpipe %u: set descriptor failed: %d\n",
+ index, (int)result);
+ goto error;
+ }
+ if (result < sizeof(*descr)) {
+ dev_err(dev, "rpipe %u: sent short descriptor "
+ "(%zd vs %zd bytes required)\n",
+ index, result, sizeof(*descr));
+ result = -EINVAL;
+ goto error;
+ }
+ result = 0;
+
+error:
+ return result;
+
+}
+
+static void rpipe_init(struct wa_rpipe *rpipe)
+{
+ kref_init(&rpipe->refcnt);
+ spin_lock_init(&rpipe->seg_lock);
+ INIT_LIST_HEAD(&rpipe->seg_list);
+}
+
+static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wa->rpipe_bm_lock, flags);
+ rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx);
+ if (rpipe_idx < wa->rpipes)
+ set_bit(rpipe_idx, wa->rpipe_bm);
+ spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags);
+
+ return rpipe_idx;
+}
+
+static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wa->rpipe_bm_lock, flags);
+ clear_bit(rpipe_idx, wa->rpipe_bm);
+ spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags);
+}
+
+void rpipe_destroy(struct kref *_rpipe)
+{
+ struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt);
+ u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+ d_fnstart(1, NULL, "(rpipe %p %u)\n", rpipe, index);
+ if (rpipe->ep)
+ rpipe->ep->hcpriv = NULL;
+ rpipe_put_idx(rpipe->wa, index);
+ wa_put(rpipe->wa);
+ kfree(rpipe);
+ d_fnend(1, NULL, "(rpipe %p %u)\n", rpipe, index);
+}
+EXPORT_SYMBOL_GPL(rpipe_destroy);
+
+/*
+ * Locate an idle rpipe, create an structure for it and return it
+ *
+ * @wa is referenced and unlocked
+ * @crs enum rpipe_attr, required endpoint characteristics
+ *
+ * The rpipe can be used only sequentially (not in parallel).
+ *
+ * The rpipe is moved into the "ready" state.
+ */
+static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs,
+ gfp_t gfp)
+{
+ int result;
+ unsigned rpipe_idx;
+ struct wa_rpipe *rpipe;
+ struct device *dev = &wa->usb_iface->dev;
+
+ d_fnstart(3, dev, "(wa %p crs 0x%02x)\n", wa, crs);
+ rpipe = kzalloc(sizeof(*rpipe), gfp);
+ if (rpipe == NULL)
+ return -ENOMEM;
+ rpipe_init(rpipe);
+
+ /* Look for an idle pipe */
+ for (rpipe_idx = 0; rpipe_idx < wa->rpipes; rpipe_idx++) {
+ rpipe_idx = rpipe_get_idx(wa, rpipe_idx);
+ if (rpipe_idx >= wa->rpipes) /* no more pipes :( */
+ break;
+ result = __rpipe_get_descr(wa, &rpipe->descr, rpipe_idx);
+ if (result < 0)
+ dev_err(dev, "Can't get descriptor for rpipe %u: %d\n",
+ rpipe_idx, result);
+ else if ((rpipe->descr.bmCharacteristics & crs) != 0)
+ goto found;
+ rpipe_put_idx(wa, rpipe_idx);
+ }
+ *prpipe = NULL;
+ kfree(rpipe);
+ d_fnend(3, dev, "(wa %p crs 0x%02x) = -ENXIO\n", wa, crs);
+ return -ENXIO;
+
+found:
+ set_bit(rpipe_idx, wa->rpipe_bm);
+ rpipe->wa = wa_get(wa);
+ *prpipe = rpipe;
+ d_fnstart(3, dev, "(wa %p crs 0x%02x) = 0\n", wa, crs);
+ return 0;
+}
+
+static int __rpipe_reset(struct wahc *wa, unsigned index)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+
+ d_printf(1, dev, "rpipe %u: reset\n", index);
+ result = usb_control_msg(
+ wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+ USB_REQ_RPIPE_RESET,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ 0, index, NULL, 0, 1000 /* FIXME: arbitrary */);
+ if (result < 0)
+ dev_err(dev, "rpipe %u: reset failed: %d\n",
+ index, result);
+ return result;
+}
+
+/*
+ * Fake companion descriptor for ep0
+ *
+ * See WUSB1.0[7.4.4], most of this is zero for bulk/int/ctl
+ */
+static struct usb_wireless_ep_comp_descriptor epc0 = {
+ .bLength = sizeof(epc0),
+ .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP,
+/* .bMaxBurst = 1, */
+ .bMaxSequence = 31,
+};
+
+/*
+ * Look for EP companion descriptor
+ *
+ * Get there, look for Inara in the endpoint's extra descriptors
+ */
+static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find(
+ struct device *dev, struct usb_host_endpoint *ep)
+{
+ void *itr;
+ size_t itr_size;
+ struct usb_descriptor_header *hdr;
+ struct usb_wireless_ep_comp_descriptor *epcd;
+
+ d_fnstart(3, dev, "(ep %p)\n", ep);
+ if (ep->desc.bEndpointAddress == 0) {
+ epcd = &epc0;
+ goto out;
+ }
+ itr = ep->extra;
+ itr_size = ep->extralen;
+ epcd = NULL;
+ while (itr_size > 0) {
+ if (itr_size < sizeof(*hdr)) {
+ dev_err(dev, "HW Bug? ep 0x%02x: extra descriptors "
+ "at offset %zu: only %zu bytes left\n",
+ ep->desc.bEndpointAddress,
+ itr - (void *) ep->extra, itr_size);
+ break;
+ }
+ hdr = itr;
+ if (hdr->bDescriptorType == USB_DT_WIRELESS_ENDPOINT_COMP) {
+ epcd = itr;
+ break;
+ }
+ if (hdr->bLength > itr_size) {
+ dev_err(dev, "HW Bug? ep 0x%02x: extra descriptor "
+ "at offset %zu (type 0x%02x) "
+ "length %d but only %zu bytes left\n",
+ ep->desc.bEndpointAddress,
+ itr - (void *) ep->extra, hdr->bDescriptorType,
+ hdr->bLength, itr_size);
+ break;
+ }
+ itr += hdr->bLength;
+ itr_size -= hdr->bDescriptorType;
+ }
+out:
+ d_fnend(3, dev, "(ep %p) = %p\n", ep, epcd);
+ return epcd;
+}
+
+/*
+ * Aim an rpipe to its device & endpoint destination
+ *
+ * Make sure we change the address to unauthenticathed if the device
+ * is WUSB and it is not authenticated.
+ */
+static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,
+ struct usb_host_endpoint *ep, struct urb *urb, gfp_t gfp)
+{
+ int result = -ENOMSG; /* better code for lack of companion? */
+ struct device *dev = &wa->usb_iface->dev;
+ struct usb_device *usb_dev = urb->dev;
+ struct usb_wireless_ep_comp_descriptor *epcd;
+ u8 unauth;
+
+ d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n",
+ rpipe, wa, ep, urb);
+ epcd = rpipe_epc_find(dev, ep);
+ if (epcd == NULL) {
+ dev_err(dev, "ep 0x%02x: can't find companion descriptor\n",
+ ep->desc.bEndpointAddress);
+ goto error;
+ }
+ unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0;
+ __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex));
+ atomic_set(&rpipe->segs_available, le16_to_cpu(rpipe->descr.wRequests));
+ /* FIXME: block allocation system; request with queuing and timeout */
+ /* FIXME: compute so seg_size > ep->maxpktsize */
+ rpipe->descr.wBlocks = cpu_to_le16(16); /* given */
+ /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */
+ rpipe->descr.wMaxPacketSize = cpu_to_le16(ep->desc.wMaxPacketSize);
+ rpipe->descr.bHSHubAddress = 0; /* reserved: zero */
+ rpipe->descr.bHSHubPort = wusb_port_no_to_idx(urb->dev->portnum);
+ /* FIXME: use maximum speed as supported or recommended by device */
+ rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ?
+ UWB_PHY_RATE_53 : UWB_PHY_RATE_200;
+ d_printf(2, dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n",
+ urb->dev->devnum, urb->dev->devnum | unauth,
+ le16_to_cpu(rpipe->descr.wRPipeIndex),
+ usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed);
+ /* see security.c:wusb_update_address() */
+ if (unlikely(urb->dev->devnum == 0x80))
+ rpipe->descr.bDeviceAddress = 0;
+ else
+ rpipe->descr.bDeviceAddress = urb->dev->devnum | unauth;
+ rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress;
+ /* FIXME: bDataSequence */
+ rpipe->descr.bDataSequence = 0;
+ /* FIXME: dwCurrentWindow */
+ rpipe->descr.dwCurrentWindow = cpu_to_le32(1);
+ /* FIXME: bMaxDataSequence */
+ rpipe->descr.bMaxDataSequence = epcd->bMaxSequence - 1;
+ rpipe->descr.bInterval = ep->desc.bInterval;
+ /* FIXME: bOverTheAirInterval */
+ rpipe->descr.bOverTheAirInterval = 0; /* 0 if not isoc */
+ /* FIXME: xmit power & preamble blah blah */
+ rpipe->descr.bmAttribute = ep->desc.bmAttributes & 0x03;
+ /* rpipe->descr.bmCharacteristics RO */
+ /* FIXME: bmRetryOptions */
+ rpipe->descr.bmRetryOptions = 15;
+ /* FIXME: use for assessing link quality? */
+ rpipe->descr.wNumTransactionErrors = 0;
+ result = __rpipe_set_descr(wa, &rpipe->descr,
+ le16_to_cpu(rpipe->descr.wRPipeIndex));
+ if (result < 0) {
+ dev_err(dev, "Cannot aim rpipe: %d\n", result);
+ goto error;
+ }
+ result = 0;
+error:
+ d_fnend(3, dev, "(rpipe %p wa %p ep %p urb %p) = %d\n",
+ rpipe, wa, ep, urb, result);
+ return result;
+}
+
+/*
+ * Check an aimed rpipe to make sure it points to where we want
+ *
+ * We use bit 19 of the Linux USB pipe bitmap for unauth vs auth
+ * space; when it is like that, we or 0x80 to make an unauth address.
+ */
+static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa,
+ const struct usb_host_endpoint *ep,
+ const struct urb *urb, gfp_t gfp)
+{
+ int result = 0; /* better code for lack of companion? */
+ struct device *dev = &wa->usb_iface->dev;
+ struct usb_device *usb_dev = urb->dev;
+ u8 unauth = (usb_dev->wusb && !usb_dev->authenticated) ? 0x80 : 0;
+ u8 portnum = wusb_port_no_to_idx(urb->dev->portnum);
+
+ d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n",
+ rpipe, wa, ep, urb);
+#define AIM_CHECK(rdf, val, text) \
+ do { \
+ if (rpipe->descr.rdf != (val)) { \
+ dev_err(dev, \
+ "rpipe aim discrepancy: " #rdf " " text "\n", \
+ rpipe->descr.rdf, (val)); \
+ result = -EINVAL; \
+ WARN_ON(1); \
+ } \
+ } while (0)
+ AIM_CHECK(wMaxPacketSize, cpu_to_le16(ep->desc.wMaxPacketSize),
+ "(%u vs %u)");
+ AIM_CHECK(bHSHubPort, portnum, "(%u vs %u)");
+ AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ?
+ UWB_PHY_RATE_53 : UWB_PHY_RATE_200,
+ "(%u vs %u)");
+ AIM_CHECK(bDeviceAddress, urb->dev->devnum | unauth, "(%u vs %u)");
+ AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)");
+ AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)");
+ AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)");
+#undef AIM_CHECK
+ return result;
+}
+
+#ifndef CONFIG_BUG
+#define CONFIG_BUG 0
+#endif
+
+/*
+ * Make sure there is an rpipe allocated for an endpoint
+ *
+ * If already allocated, we just refcount it; if not, we get an
+ * idle one, aim it to the right location and take it.
+ *
+ * Attaches to ep->hcpriv and rpipe->ep to ep.
+ */
+int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep,
+ struct urb *urb, gfp_t gfp)
+{
+ int result = 0;
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_rpipe *rpipe;
+ u8 eptype;
+
+ d_fnstart(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb,
+ gfp);
+ mutex_lock(&wa->rpipe_mutex);
+ rpipe = ep->hcpriv;
+ if (rpipe != NULL) {
+ if (CONFIG_BUG == 1) {
+ result = rpipe_check_aim(rpipe, wa, ep, urb, gfp);
+ if (result < 0)
+ goto error;
+ }
+ __rpipe_get(rpipe);
+ d_printf(2, dev, "ep 0x%02x: reusing rpipe %u\n",
+ ep->desc.bEndpointAddress,
+ le16_to_cpu(rpipe->descr.wRPipeIndex));
+ } else {
+ /* hmm, assign idle rpipe, aim it */
+ result = -ENOBUFS;
+ eptype = ep->desc.bmAttributes & 0x03;
+ result = rpipe_get_idle(&rpipe, wa, 1 << eptype, gfp);
+ if (result < 0)
+ goto error;
+ result = rpipe_aim(rpipe, wa, ep, urb, gfp);
+ if (result < 0) {
+ rpipe_put(rpipe);
+ goto error;
+ }
+ ep->hcpriv = rpipe;
+ rpipe->ep = ep;
+ __rpipe_get(rpipe); /* for caching into ep->hcpriv */
+ d_printf(2, dev, "ep 0x%02x: using rpipe %u\n",
+ ep->desc.bEndpointAddress,
+ le16_to_cpu(rpipe->descr.wRPipeIndex));
+ }
+ d_dump(4, dev, &rpipe->descr, sizeof(rpipe->descr));
+error:
+ mutex_unlock(&wa->rpipe_mutex);
+ d_fnend(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, gfp);
+ return result;
+}
+
+/*
+ * Allocate the bitmap for each rpipe.
+ */
+int wa_rpipes_create(struct wahc *wa)
+{
+ wa->rpipes = wa->wa_descr->wNumRPipes;
+ wa->rpipe_bm = kzalloc(BITS_TO_LONGS(wa->rpipes)*sizeof(unsigned long),
+ GFP_KERNEL);
+ if (wa->rpipe_bm == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+void wa_rpipes_destroy(struct wahc *wa)
+{
+ struct device *dev = &wa->usb_iface->dev;
+ d_fnstart(3, dev, "(wa %p)\n", wa);
+ if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) {
+ char buf[256];
+ WARN_ON(1);
+ bitmap_scnprintf(buf, sizeof(buf), wa->rpipe_bm, wa->rpipes);
+ dev_err(dev, "BUG: pipes not released on exit: %s\n", buf);
+ }
+ kfree(wa->rpipe_bm);
+ d_fnend(3, dev, "(wa %p)\n", wa);
+}
+
+/*
+ * Release resources allocated for an endpoint
+ *
+ * If there is an associated rpipe to this endpoint, Abort any pending
+ * transfers and put it. If the rpipe ends up being destroyed,
+ * __rpipe_destroy() will cleanup ep->hcpriv.
+ *
+ * This is called before calling hcd->stop(), so you don't need to do
+ * anything else in there.
+ */
+void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep)
+{
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_rpipe *rpipe;
+ d_fnstart(2, dev, "(wa %p ep %p)\n", wa, ep);
+ mutex_lock(&wa->rpipe_mutex);
+ rpipe = ep->hcpriv;
+ if (rpipe != NULL) {
+ unsigned rc = atomic_read(&rpipe->refcnt.refcount);
+ int result;
+ u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+ if (rc != 1)
+ d_printf(1, dev, "(wa %p ep %p) rpipe %p refcnt %u\n",
+ wa, ep, rpipe, rc);
+
+ d_printf(1, dev, "rpipe %u: abort\n", index);
+ result = usb_control_msg(
+ wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+ USB_REQ_RPIPE_ABORT,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ 0, index, NULL, 0, 1000 /* FIXME: arbitrary */);
+ if (result < 0 && result != -ENODEV /* dev is gone */)
+ d_printf(1, dev, "(wa %p rpipe %u): abort failed: %d\n",
+ wa, index, result);
+ rpipe_put(rpipe);
+ }
+ mutex_unlock(&wa->rpipe_mutex);
+ d_fnend(2, dev, "(wa %p ep %p)\n", wa, ep);
+ return;
+}
+EXPORT_SYMBOL_GPL(rpipe_ep_disable);
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
new file mode 100644
index 00000000000..c038635d1c6
--- /dev/null
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -0,0 +1,1709 @@
+/*
+ * WUSB Wire Adapter
+ * Data transfer and URB enqueing
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * How transfers work: get a buffer, break it up in segments (segment
+ * size is a multiple of the maxpacket size). For each segment issue a
+ * segment request (struct wa_xfer_*), then send the data buffer if
+ * out or nothing if in (all over the DTO endpoint).
+ *
+ * For each submitted segment request, a notification will come over
+ * the NEP endpoint and a transfer result (struct xfer_result) will
+ * arrive in the DTI URB. Read it, get the xfer ID, see if there is
+ * data coming (inbound transfer), schedule a read and handle it.
+ *
+ * Sounds simple, it is a pain to implement.
+ *
+ *
+ * ENTRY POINTS
+ *
+ * FIXME
+ *
+ * LIFE CYCLE / STATE DIAGRAM
+ *
+ * FIXME
+ *
+ * THIS CODE IS DISGUSTING
+ *
+ * Warned you are; it's my second try and still not happy with it.
+ *
+ * NOTES:
+ *
+ * - No iso
+ *
+ * - Supports DMA xfers, control, bulk and maybe interrupt
+ *
+ * - Does not recycle unused rpipes
+ *
+ * An rpipe is assigned to an endpoint the first time it is used,
+ * and then it's there, assigned, until the endpoint is disabled
+ * (destroyed [{h,d}wahc_op_ep_disable()]. The assignment of the
+ * rpipe to the endpoint is done under the wa->rpipe_sem semaphore
+ * (should be a mutex).
+ *
+ * Two methods it could be done:
+ *
+ * (a) set up a timer everytime an rpipe's use count drops to 1
+ * (which means unused) or when a transfer ends. Reset the
+ * timer when a xfer is queued. If the timer expires, release
+ * the rpipe [see rpipe_ep_disable()].
+ *
+ * (b) when looking for free rpipes to attach [rpipe_get_by_ep()],
+ * when none are found go over the list, check their endpoint
+ * and their activity record (if no last-xfer-done-ts in the
+ * last x seconds) take it
+ *
+ * However, due to the fact that we have a set of limited
+ * resources (max-segments-at-the-same-time per xfer,
+ * xfers-per-ripe, blocks-per-rpipe, rpipes-per-host), at the end
+ * we are going to have to rebuild all this based on an scheduler,
+ * to where we have a list of transactions to do and based on the
+ * availability of the different requried components (blocks,
+ * rpipes, segment slots, etc), we go scheduling them. Painful.
+ */
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/hash.h>
+#include "wa-hc.h"
+#include "wusbhc.h"
+
+#undef D_LOCAL
+#define D_LOCAL 0 /* 0 disabled, > 0 different levels... */
+#include <linux/uwb/debug.h>
+
+enum {
+ WA_SEGS_MAX = 255,
+};
+
+enum wa_seg_status {
+ WA_SEG_NOTREADY,
+ WA_SEG_READY,
+ WA_SEG_DELAYED,
+ WA_SEG_SUBMITTED,
+ WA_SEG_PENDING,
+ WA_SEG_DTI_PENDING,
+ WA_SEG_DONE,
+ WA_SEG_ERROR,
+ WA_SEG_ABORTED,
+};
+
+static void wa_xfer_delayed_run(struct wa_rpipe *);
+
+/*
+ * Life cycle governed by 'struct urb' (the refcount of the struct is
+ * that of the 'struct urb' and usb_free_urb() would free the whole
+ * struct).
+ */
+struct wa_seg {
+ struct urb urb;
+ struct urb *dto_urb; /* for data output? */
+ struct list_head list_node; /* for rpipe->req_list */
+ struct wa_xfer *xfer; /* out xfer */
+ u8 index; /* which segment we are */
+ enum wa_seg_status status;
+ ssize_t result; /* bytes xfered or error */
+ struct wa_xfer_hdr xfer_hdr;
+ u8 xfer_extra[]; /* xtra space for xfer_hdr_ctl */
+};
+
+static void wa_seg_init(struct wa_seg *seg)
+{
+ /* usb_init_urb() repeats a lot of work, so we do it here */
+ kref_init(&seg->urb.kref);
+}
+
+/*
+ * Protected by xfer->lock
+ *
+ */
+struct wa_xfer {
+ struct kref refcnt;
+ struct list_head list_node;
+ spinlock_t lock;
+ u32 id;
+
+ struct wahc *wa; /* Wire adapter we are plugged to */
+ struct usb_host_endpoint *ep;
+ struct urb *urb; /* URB we are transfering for */
+ struct wa_seg **seg; /* transfer segments */
+ u8 segs, segs_submitted, segs_done;
+ unsigned is_inbound:1;
+ unsigned is_dma:1;
+ size_t seg_size;
+ int result;
+
+ gfp_t gfp; /* allocation mask */
+
+ struct wusb_dev *wusb_dev; /* for activity timestamps */
+};
+
+static inline void wa_xfer_init(struct wa_xfer *xfer)
+{
+ kref_init(&xfer->refcnt);
+ INIT_LIST_HEAD(&xfer->list_node);
+ spin_lock_init(&xfer->lock);
+}
+
+/*
+ * Destory a transfer structure
+ *
+ * Note that the xfer->seg[index] thingies follow the URB life cycle,
+ * so we need to put them, not free them.
+ */
+static void wa_xfer_destroy(struct kref *_xfer)
+{
+ struct wa_xfer *xfer = container_of(_xfer, struct wa_xfer, refcnt);
+ if (xfer->seg) {
+ unsigned cnt;
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ if (xfer->is_inbound)
+ usb_put_urb(xfer->seg[cnt]->dto_urb);
+ usb_put_urb(&xfer->seg[cnt]->urb);
+ }
+ }
+ kfree(xfer);
+ d_printf(2, NULL, "xfer %p destroyed\n", xfer);
+}
+
+static void wa_xfer_get(struct wa_xfer *xfer)
+{
+ kref_get(&xfer->refcnt);
+}
+
+static void wa_xfer_put(struct wa_xfer *xfer)
+{
+ d_fnstart(3, NULL, "(xfer %p) -- ref count bef put %d\n",
+ xfer, atomic_read(&xfer->refcnt.refcount));
+ kref_put(&xfer->refcnt, wa_xfer_destroy);
+ d_fnend(3, NULL, "(xfer %p) = void\n", xfer);
+}
+
+/*
+ * xfer is referenced
+ *
+ * xfer->lock has to be unlocked
+ *
+ * We take xfer->lock for setting the result; this is a barrier
+ * against drivers/usb/core/hcd.c:unlink1() being called after we call
+ * usb_hcd_giveback_urb() and wa_urb_dequeue() trying to get a
+ * reference to the transfer.
+ */
+static void wa_xfer_giveback(struct wa_xfer *xfer)
+{
+ unsigned long flags;
+ d_fnstart(3, NULL, "(xfer %p)\n", xfer);
+ spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags);
+ list_del_init(&xfer->list_node);
+ spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags);
+ /* FIXME: segmentation broken -- kills DWA */
+ wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result);
+ wa_put(xfer->wa);
+ wa_xfer_put(xfer);
+ d_fnend(3, NULL, "(xfer %p) = void\n", xfer);
+}
+
+/*
+ * xfer is referenced
+ *
+ * xfer->lock has to be unlocked
+ */
+static void wa_xfer_completion(struct wa_xfer *xfer)
+{
+ d_fnstart(3, NULL, "(xfer %p)\n", xfer);
+ if (xfer->wusb_dev)
+ wusb_dev_put(xfer->wusb_dev);
+ rpipe_put(xfer->ep->hcpriv);
+ wa_xfer_giveback(xfer);
+ d_fnend(3, NULL, "(xfer %p) = void\n", xfer);
+ return;
+}
+
+/*
+ * If transfer is done, wrap it up and return true
+ *
+ * xfer->lock has to be locked
+ */
+static unsigned __wa_xfer_is_done(struct wa_xfer *xfer)
+{
+ unsigned result, cnt;
+ struct wa_seg *seg;
+ struct urb *urb = xfer->urb;
+ unsigned found_short = 0;
+
+ d_fnstart(3, NULL, "(xfer %p)\n", xfer);
+ result = xfer->segs_done == xfer->segs_submitted;
+ if (result == 0)
+ goto out;
+ urb->actual_length = 0;
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ seg = xfer->seg[cnt];
+ switch (seg->status) {
+ case WA_SEG_DONE:
+ if (found_short && seg->result > 0) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "xfer %p#%u: bad short "
+ "segments (%zu)\n", xfer, cnt,
+ seg->result);
+ urb->status = -EINVAL;
+ goto out;
+ }
+ urb->actual_length += seg->result;
+ if (seg->result < xfer->seg_size
+ && cnt != xfer->segs-1)
+ found_short = 1;
+ d_printf(2, NULL, "xfer %p#%u: DONE short %d "
+ "result %zu urb->actual_length %d\n",
+ xfer, seg->index, found_short, seg->result,
+ urb->actual_length);
+ break;
+ case WA_SEG_ERROR:
+ xfer->result = seg->result;
+ d_printf(2, NULL, "xfer %p#%u: ERROR result %zu\n",
+ xfer, seg->index, seg->result);
+ goto out;
+ case WA_SEG_ABORTED:
+ WARN_ON(urb->status != -ECONNRESET
+ && urb->status != -ENOENT);
+ d_printf(2, NULL, "xfer %p#%u ABORTED: result %d\n",
+ xfer, seg->index, urb->status);
+ xfer->result = urb->status;
+ goto out;
+ default:
+ /* if (printk_ratelimit()) */
+ printk(KERN_ERR "xfer %p#%u: "
+ "is_done bad state %d\n",
+ xfer, cnt, seg->status);
+ xfer->result = -EINVAL;
+ WARN_ON(1);
+ goto out;
+ }
+ }
+ xfer->result = 0;
+out:
+ d_fnend(3, NULL, "(xfer %p) = void\n", xfer);
+ return result;
+}
+
+/*
+ * Initialize a transfer's ID
+ *
+ * We need to use a sequential number; if we use the pointer or the
+ * hash of the pointer, it can repeat over sequential transfers and
+ * then it will confuse the HWA....wonder why in hell they put a 32
+ * bit handle in there then.
+ */
+static void wa_xfer_id_init(struct wa_xfer *xfer)
+{
+ xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count);
+}
+
+/*
+ * Return the xfer's ID associated with xfer
+ *
+ * Need to generate a
+ */
+static u32 wa_xfer_id(struct wa_xfer *xfer)
+{
+ return xfer->id;
+}
+
+/*
+ * Search for a transfer list ID on the HCD's URB list
+ *
+ * For 32 bit architectures, we use the pointer itself; for 64 bits, a
+ * 32-bit hash of the pointer.
+ *
+ * @returns NULL if not found.
+ */
+static struct wa_xfer *wa_xfer_get_by_id(struct wahc *wa, u32 id)
+{
+ unsigned long flags;
+ struct wa_xfer *xfer_itr;
+ spin_lock_irqsave(&wa->xfer_list_lock, flags);
+ list_for_each_entry(xfer_itr, &wa->xfer_list, list_node) {
+ if (id == xfer_itr->id) {
+ wa_xfer_get(xfer_itr);
+ goto out;
+ }
+ }
+ xfer_itr = NULL;
+out:
+ spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
+ return xfer_itr;
+}
+
+struct wa_xfer_abort_buffer {
+ struct urb urb;
+ struct wa_xfer_abort cmd;
+};
+
+static void __wa_xfer_abort_cb(struct urb *urb)
+{
+ struct wa_xfer_abort_buffer *b = urb->context;
+ usb_put_urb(&b->urb);
+}
+
+/*
+ * Aborts an ongoing transaction
+ *
+ * Assumes the transfer is referenced and locked and in a submitted
+ * state (mainly that there is an endpoint/rpipe assigned).
+ *
+ * The callback (see above) does nothing but freeing up the data by
+ * putting the URB. Because the URB is allocated at the head of the
+ * struct, the whole space we allocated is kfreed.
+ *
+ * We'll get an 'aborted transaction' xfer result on DTI, that'll
+ * politely ignore because at this point the transaction has been
+ * marked as aborted already.
+ */
+static void __wa_xfer_abort(struct wa_xfer *xfer)
+{
+ int result;
+ struct device *dev = &xfer->wa->usb_iface->dev;
+ struct wa_xfer_abort_buffer *b;
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+ b = kmalloc(sizeof(*b), GFP_ATOMIC);
+ if (b == NULL)
+ goto error_kmalloc;
+ b->cmd.bLength = sizeof(b->cmd);
+ b->cmd.bRequestType = WA_XFER_ABORT;
+ b->cmd.wRPipe = rpipe->descr.wRPipeIndex;
+ b->cmd.dwTransferID = wa_xfer_id(xfer);
+
+ usb_init_urb(&b->urb);
+ usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev,
+ usb_sndbulkpipe(xfer->wa->usb_dev,
+ xfer->wa->dto_epd->bEndpointAddress),
+ &b->cmd, sizeof(b->cmd), __wa_xfer_abort_cb, b);
+ result = usb_submit_urb(&b->urb, GFP_ATOMIC);
+ if (result < 0)
+ goto error_submit;
+ return; /* callback frees! */
+
+
+error_submit:
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p: Can't submit abort request: %d\n",
+ xfer, result);
+ kfree(b);
+error_kmalloc:
+ return;
+
+}
+
+/*
+ *
+ * @returns < 0 on error, transfer segment request size if ok
+ */
+static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer,
+ enum wa_xfer_type *pxfer_type)
+{
+ ssize_t result;
+ struct device *dev = &xfer->wa->usb_iface->dev;
+ size_t maxpktsize;
+ struct urb *urb = xfer->urb;
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+ d_fnstart(3, dev, "(xfer %p [rpipe %p] urb %p)\n",
+ xfer, rpipe, urb);
+ switch (rpipe->descr.bmAttribute & 0x3) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ *pxfer_type = WA_XFER_TYPE_CTL;
+ result = sizeof(struct wa_xfer_ctl);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ case USB_ENDPOINT_XFER_BULK:
+ *pxfer_type = WA_XFER_TYPE_BI;
+ result = sizeof(struct wa_xfer_bi);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ dev_err(dev, "FIXME: ISOC not implemented\n");
+ result = -ENOSYS;
+ goto error;
+ default:
+ /* never happens */
+ BUG();
+ result = -EINVAL; /* shut gcc up */
+ };
+ xfer->is_inbound = urb->pipe & USB_DIR_IN ? 1 : 0;
+ xfer->is_dma = urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? 1 : 0;
+ xfer->seg_size = le16_to_cpu(rpipe->descr.wBlocks)
+ * 1 << (xfer->wa->wa_descr->bRPipeBlockSize - 1);
+ /* Compute the segment size and make sure it is a multiple of
+ * the maxpktsize (WUSB1.0[8.3.3.1])...not really too much of
+ * a check (FIXME) */
+ maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize);
+ if (xfer->seg_size < maxpktsize) {
+ dev_err(dev, "HW BUG? seg_size %zu smaller than maxpktsize "
+ "%zu\n", xfer->seg_size, maxpktsize);
+ result = -EINVAL;
+ goto error;
+ }
+ xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize;
+ xfer->segs = (urb->transfer_buffer_length + xfer->seg_size - 1)
+ / xfer->seg_size;
+ if (xfer->segs >= WA_SEGS_MAX) {
+ dev_err(dev, "BUG? ops, number of segments %d bigger than %d\n",
+ (int)(urb->transfer_buffer_length / xfer->seg_size),
+ WA_SEGS_MAX);
+ result = -EINVAL;
+ goto error;
+ }
+ if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL)
+ xfer->segs = 1;
+error:
+ d_fnend(3, dev, "(xfer %p [rpipe %p] urb %p) = %d\n",
+ xfer, rpipe, urb, (int)result);
+ return result;
+}
+
+/** Fill in the common request header and xfer-type specific data. */
+static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer,
+ struct wa_xfer_hdr *xfer_hdr0,
+ enum wa_xfer_type xfer_type,
+ size_t xfer_hdr_size)
+{
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+ xfer_hdr0 = &xfer->seg[0]->xfer_hdr;
+ xfer_hdr0->bLength = xfer_hdr_size;
+ xfer_hdr0->bRequestType = xfer_type;
+ xfer_hdr0->wRPipe = rpipe->descr.wRPipeIndex;
+ xfer_hdr0->dwTransferID = wa_xfer_id(xfer);
+ xfer_hdr0->bTransferSegment = 0;
+ switch (xfer_type) {
+ case WA_XFER_TYPE_CTL: {
+ struct wa_xfer_ctl *xfer_ctl =
+ container_of(xfer_hdr0, struct wa_xfer_ctl, hdr);
+ xfer_ctl->bmAttribute = xfer->is_inbound ? 1 : 0;
+ BUG_ON(xfer->urb->transfer_flags & URB_NO_SETUP_DMA_MAP
+ && xfer->urb->setup_packet == NULL);
+ memcpy(&xfer_ctl->baSetupData, xfer->urb->setup_packet,
+ sizeof(xfer_ctl->baSetupData));
+ break;
+ }
+ case WA_XFER_TYPE_BI:
+ break;
+ case WA_XFER_TYPE_ISO:
+ printk(KERN_ERR "FIXME: ISOC not implemented\n");
+ default:
+ BUG();
+ };
+}
+
+/*
+ * Callback for the OUT data phase of the segment request
+ *
+ * Check wa_seg_cb(); most comments also apply here because this
+ * function does almost the same thing and they work closely
+ * together.
+ *
+ * If the seg request has failed but this DTO phase has suceeded,
+ * wa_seg_cb() has already failed the segment and moved the
+ * status to WA_SEG_ERROR, so this will go through 'case 0' and
+ * effectively do nothing.
+ */
+static void wa_seg_dto_cb(struct urb *urb)
+{
+ struct wa_seg *seg = urb->context;
+ struct wa_xfer *xfer = seg->xfer;
+ struct wahc *wa;
+ struct device *dev;
+ struct wa_rpipe *rpipe;
+ unsigned long flags;
+ unsigned rpipe_ready = 0;
+ u8 done = 0;
+
+ d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status);
+ switch (urb->status) {
+ case 0:
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ d_printf(2, dev, "xfer %p#%u: data out done (%d bytes)\n",
+ xfer, seg->index, urb->actual_length);
+ if (seg->status < WA_SEG_PENDING)
+ seg->status = WA_SEG_PENDING;
+ seg->result = urb->actual_length;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ break;
+ case -ECONNRESET: /* URB unlinked; no need to do anything */
+ case -ENOENT: /* as it was done by the who unlinked us */
+ break;
+ default: /* Other errors ... */
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ rpipe = xfer->ep->hcpriv;
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p#%u: data out error %d\n",
+ xfer, seg->index, urb->status);
+ if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)){
+ dev_err(dev, "DTO: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ if (seg->status != WA_SEG_ERROR) {
+ seg->status = WA_SEG_ERROR;
+ seg->result = urb->status;
+ xfer->segs_done++;
+ __wa_xfer_abort(xfer);
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_is_done(xfer);
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ }
+ d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status);
+}
+
+/*
+ * Callback for the segment request
+ *
+ * If succesful transition state (unless already transitioned or
+ * outbound transfer); otherwise, take a note of the error, mark this
+ * segment done and try completion.
+ *
+ * Note we don't access until we are sure that the transfer hasn't
+ * been cancelled (ECONNRESET, ENOENT), which could mean that
+ * seg->xfer could be already gone.
+ *
+ * We have to check before setting the status to WA_SEG_PENDING
+ * because sometimes the xfer result callback arrives before this
+ * callback (geeeeeeze), so it might happen that we are already in
+ * another state. As well, we don't set it if the transfer is inbound,
+ * as in that case, wa_seg_dto_cb will do it when the OUT data phase
+ * finishes.
+ */
+static void wa_seg_cb(struct urb *urb)
+{
+ struct wa_seg *seg = urb->context;
+ struct wa_xfer *xfer = seg->xfer;
+ struct wahc *wa;
+ struct device *dev;
+ struct wa_rpipe *rpipe;
+ unsigned long flags;
+ unsigned rpipe_ready;
+ u8 done = 0;
+
+ d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status);
+ switch (urb->status) {
+ case 0:
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ d_printf(2, dev, "xfer %p#%u: request done\n",
+ xfer, seg->index);
+ if (xfer->is_inbound && seg->status < WA_SEG_PENDING)
+ seg->status = WA_SEG_PENDING;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ break;
+ case -ECONNRESET: /* URB unlinked; no need to do anything */
+ case -ENOENT: /* as it was done by the who unlinked us */
+ break;
+ default: /* Other errors ... */
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ rpipe = xfer->ep->hcpriv;
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p#%u: request error %d\n",
+ xfer, seg->index, urb->status);
+ if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)){
+ dev_err(dev, "DTO: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ usb_unlink_urb(seg->dto_urb);
+ seg->status = WA_SEG_ERROR;
+ seg->result = urb->status;
+ xfer->segs_done++;
+ __wa_xfer_abort(xfer);
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_is_done(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ }
+ d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status);
+}
+
+/*
+ * Allocate the segs array and initialize each of them
+ *
+ * The segments are freed by wa_xfer_destroy() when the xfer use count
+ * drops to zero; however, because each segment is given the same life
+ * cycle as the USB URB it contains, it is actually freed by
+ * usb_put_urb() on the contained USB URB (twisted, eh?).
+ */
+static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
+{
+ int result, cnt;
+ size_t alloc_size = sizeof(*xfer->seg[0])
+ - sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size;
+ struct usb_device *usb_dev = xfer->wa->usb_dev;
+ const struct usb_endpoint_descriptor *dto_epd = xfer->wa->dto_epd;
+ struct wa_seg *seg;
+ size_t buf_itr, buf_size, buf_itr_size;
+
+ result = -ENOMEM;
+ xfer->seg = kcalloc(xfer->segs, sizeof(xfer->seg[0]), GFP_ATOMIC);
+ if (xfer->seg == NULL)
+ goto error_segs_kzalloc;
+ buf_itr = 0;
+ buf_size = xfer->urb->transfer_buffer_length;
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ seg = xfer->seg[cnt] = kzalloc(alloc_size, GFP_ATOMIC);
+ if (seg == NULL)
+ goto error_seg_kzalloc;
+ wa_seg_init(seg);
+ seg->xfer = xfer;
+ seg->index = cnt;
+ usb_fill_bulk_urb(&seg->urb, usb_dev,
+ usb_sndbulkpipe(usb_dev,
+ dto_epd->bEndpointAddress),
+ &seg->xfer_hdr, xfer_hdr_size,
+ wa_seg_cb, seg);
+ buf_itr_size = buf_size > xfer->seg_size ?
+ xfer->seg_size : buf_size;
+ if (xfer->is_inbound == 0 && buf_size > 0) {
+ seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (seg->dto_urb == NULL)
+ goto error_dto_alloc;
+ usb_fill_bulk_urb(
+ seg->dto_urb, usb_dev,
+ usb_sndbulkpipe(usb_dev,
+ dto_epd->bEndpointAddress),
+ NULL, 0, wa_seg_dto_cb, seg);
+ if (xfer->is_dma) {
+ seg->dto_urb->transfer_dma =
+ xfer->urb->transfer_dma + buf_itr;
+ seg->dto_urb->transfer_flags |=
+ URB_NO_TRANSFER_DMA_MAP;
+ } else
+ seg->dto_urb->transfer_buffer =
+ xfer->urb->transfer_buffer + buf_itr;
+ seg->dto_urb->transfer_buffer_length = buf_itr_size;
+ }
+ seg->status = WA_SEG_READY;
+ buf_itr += buf_itr_size;
+ buf_size -= buf_itr_size;
+ }
+ return 0;
+
+error_dto_alloc:
+ kfree(xfer->seg[cnt]);
+ cnt--;
+error_seg_kzalloc:
+ /* use the fact that cnt is left at were it failed */
+ for (; cnt > 0; cnt--) {
+ if (xfer->is_inbound == 0)
+ kfree(xfer->seg[cnt]->dto_urb);
+ kfree(xfer->seg[cnt]);
+ }
+error_segs_kzalloc:
+ return result;
+}
+
+/*
+ * Allocates all the stuff needed to submit a transfer
+ *
+ * Breaks the whole data buffer in a list of segments, each one has a
+ * structure allocated to it and linked in xfer->seg[index]
+ *
+ * FIXME: merge setup_segs() and the last part of this function, no
+ * need to do two for loops when we could run everything in a
+ * single one
+ */
+static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb)
+{
+ int result;
+ struct device *dev = &xfer->wa->usb_iface->dev;
+ enum wa_xfer_type xfer_type = 0; /* shut up GCC */
+ size_t xfer_hdr_size, cnt, transfer_size;
+ struct wa_xfer_hdr *xfer_hdr0, *xfer_hdr;
+
+ d_fnstart(3, dev, "(xfer %p [rpipe %p] urb %p)\n",
+ xfer, xfer->ep->hcpriv, urb);
+
+ result = __wa_xfer_setup_sizes(xfer, &xfer_type);
+ if (result < 0)
+ goto error_setup_sizes;
+ xfer_hdr_size = result;
+ result = __wa_xfer_setup_segs(xfer, xfer_hdr_size);
+ if (result < 0) {
+ dev_err(dev, "xfer %p: Failed to allocate %d segments: %d\n",
+ xfer, xfer->segs, result);
+ goto error_setup_segs;
+ }
+ /* Fill the first header */
+ xfer_hdr0 = &xfer->seg[0]->xfer_hdr;
+ wa_xfer_id_init(xfer);
+ __wa_xfer_setup_hdr0(xfer, xfer_hdr0, xfer_type, xfer_hdr_size);
+
+ /* Fill remainig headers */
+ xfer_hdr = xfer_hdr0;
+ transfer_size = urb->transfer_buffer_length;
+ xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ?
+ xfer->seg_size : transfer_size;
+ transfer_size -= xfer->seg_size;
+ for (cnt = 1; cnt < xfer->segs; cnt++) {
+ xfer_hdr = &xfer->seg[cnt]->xfer_hdr;
+ memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size);
+ xfer_hdr->bTransferSegment = cnt;
+ xfer_hdr->dwTransferLength = transfer_size > xfer->seg_size ?
+ cpu_to_le32(xfer->seg_size)
+ : cpu_to_le32(transfer_size);
+ xfer->seg[cnt]->status = WA_SEG_READY;
+ transfer_size -= xfer->seg_size;
+ }
+ xfer_hdr->bTransferSegment |= 0x80; /* this is the last segment */
+ result = 0;
+error_setup_segs:
+error_setup_sizes:
+ d_fnend(3, dev, "(xfer %p [rpipe %p] urb %p) = %d\n",
+ xfer, xfer->ep->hcpriv, urb, result);
+ return result;
+}
+
+/*
+ *
+ *
+ * rpipe->seg_lock is held!
+ */
+static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
+ struct wa_seg *seg)
+{
+ int result;
+ result = usb_submit_urb(&seg->urb, GFP_ATOMIC);
+ if (result < 0) {
+ printk(KERN_ERR "xfer %p#%u: REQ submit failed: %d\n",
+ xfer, seg->index, result);
+ goto error_seg_submit;
+ }
+ if (seg->dto_urb) {
+ result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
+ if (result < 0) {
+ printk(KERN_ERR "xfer %p#%u: DTO submit failed: %d\n",
+ xfer, seg->index, result);
+ goto error_dto_submit;
+ }
+ }
+ seg->status = WA_SEG_SUBMITTED;
+ rpipe_avail_dec(rpipe);
+ return 0;
+
+error_dto_submit:
+ usb_unlink_urb(&seg->urb);
+error_seg_submit:
+ seg->status = WA_SEG_ERROR;
+ seg->result = result;
+ return result;
+}
+
+/*
+ * Execute more queued request segments until the maximum concurrent allowed
+ *
+ * The ugly unlock/lock sequence on the error path is needed as the
+ * xfer->lock normally nests the seg_lock and not viceversa.
+ *
+ */
+static void wa_xfer_delayed_run(struct wa_rpipe *rpipe)
+{
+ int result;
+ struct device *dev = &rpipe->wa->usb_iface->dev;
+ struct wa_seg *seg;
+ struct wa_xfer *xfer;
+ unsigned long flags;
+
+ d_fnstart(1, dev, "(rpipe #%d) %d segments available\n",
+ le16_to_cpu(rpipe->descr.wRPipeIndex),
+ atomic_read(&rpipe->segs_available));
+ spin_lock_irqsave(&rpipe->seg_lock, flags);
+ while (atomic_read(&rpipe->segs_available) > 0
+ && !list_empty(&rpipe->seg_list)) {
+ seg = list_entry(rpipe->seg_list.next, struct wa_seg,
+ list_node);
+ list_del(&seg->list_node);
+ xfer = seg->xfer;
+ result = __wa_seg_submit(rpipe, xfer, seg);
+ d_printf(1, dev, "xfer %p#%u submitted from delayed "
+ "[%d segments available] %d\n",
+ xfer, seg->index,
+ atomic_read(&rpipe->segs_available), result);
+ if (unlikely(result < 0)) {
+ spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+ spin_lock_irqsave(&xfer->lock, flags);
+ __wa_xfer_abort(xfer);
+ xfer->segs_done++;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ spin_lock_irqsave(&rpipe->seg_lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+ d_fnend(1, dev, "(rpipe #%d) = void, %d segments available\n",
+ le16_to_cpu(rpipe->descr.wRPipeIndex),
+ atomic_read(&rpipe->segs_available));
+
+}
+
+/*
+ *
+ * xfer->lock is taken
+ *
+ * On failure submitting we just stop submitting and return error;
+ * wa_urb_enqueue_b() will execute the completion path
+ */
+static int __wa_xfer_submit(struct wa_xfer *xfer)
+{
+ int result;
+ struct wahc *wa = xfer->wa;
+ struct device *dev = &wa->usb_iface->dev;
+ unsigned cnt;
+ struct wa_seg *seg;
+ unsigned long flags;
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+ size_t maxrequests = le16_to_cpu(rpipe->descr.wRequests);
+ u8 available;
+ u8 empty;
+
+ d_fnstart(3, dev, "(xfer %p [rpipe %p])\n",
+ xfer, xfer->ep->hcpriv);
+
+ spin_lock_irqsave(&wa->xfer_list_lock, flags);
+ list_add_tail(&xfer->list_node, &wa->xfer_list);
+ spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
+
+ BUG_ON(atomic_read(&rpipe->segs_available) > maxrequests);
+ result = 0;
+ spin_lock_irqsave(&rpipe->seg_lock, flags);
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ available = atomic_read(&rpipe->segs_available);
+ empty = list_empty(&rpipe->seg_list);
+ seg = xfer->seg[cnt];
+ d_printf(2, dev, "xfer %p#%u: available %u empty %u (%s)\n",
+ xfer, cnt, available, empty,
+ available == 0 || !empty ? "delayed" : "submitted");
+ if (available == 0 || !empty) {
+ d_printf(1, dev, "xfer %p#%u: delayed\n", xfer, cnt);
+ seg->status = WA_SEG_DELAYED;
+ list_add_tail(&seg->list_node, &rpipe->seg_list);
+ } else {
+ result = __wa_seg_submit(rpipe, xfer, seg);
+ if (result < 0)
+ goto error_seg_submit;
+ }
+ xfer->segs_submitted++;
+ }
+ spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+ d_fnend(3, dev, "(xfer %p [rpipe %p]) = void\n", xfer,
+ xfer->ep->hcpriv);
+ return result;
+
+error_seg_submit:
+ __wa_xfer_abort(xfer);
+ spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+ d_fnend(3, dev, "(xfer %p [rpipe %p]) = void\n", xfer,
+ xfer->ep->hcpriv);
+ return result;
+}
+
+/*
+ * Second part of a URB/transfer enqueuement
+ *
+ * Assumes this comes from wa_urb_enqueue() [maybe through
+ * wa_urb_enqueue_run()]. At this point:
+ *
+ * xfer->wa filled and refcounted
+ * xfer->ep filled with rpipe refcounted if
+ * delayed == 0
+ * xfer->urb filled and refcounted (this is the case when called
+ * from wa_urb_enqueue() as we come from usb_submit_urb()
+ * and when called by wa_urb_enqueue_run(), as we took an
+ * extra ref dropped by _run() after we return).
+ * xfer->gfp filled
+ *
+ * If we fail at __wa_xfer_submit(), then we just check if we are done
+ * and if so, we run the completion procedure. However, if we are not
+ * yet done, we do nothing and wait for the completion handlers from
+ * the submitted URBs or from the xfer-result path to kick in. If xfer
+ * result never kicks in, the xfer will timeout from the USB code and
+ * dequeue() will be called.
+ */
+static void wa_urb_enqueue_b(struct wa_xfer *xfer)
+{
+ int result;
+ unsigned long flags;
+ struct urb *urb = xfer->urb;
+ struct wahc *wa = xfer->wa;
+ struct wusbhc *wusbhc = wa->wusb;
+ struct device *dev = &wa->usb_iface->dev;
+ struct wusb_dev *wusb_dev;
+ unsigned done;
+
+ d_fnstart(3, dev, "(wa %p urb %p)\n", wa, urb);
+ result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp);
+ if (result < 0)
+ goto error_rpipe_get;
+ result = -ENODEV;
+ /* FIXME: segmentation broken -- kills DWA */
+ mutex_lock(&wusbhc->mutex); /* get a WUSB dev */
+ if (urb->dev == NULL)
+ goto error_dev_gone;
+ wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev);
+ if (wusb_dev == NULL) {
+ mutex_unlock(&wusbhc->mutex);
+ goto error_dev_gone;
+ }
+ mutex_unlock(&wusbhc->mutex);
+
+ spin_lock_irqsave(&xfer->lock, flags);
+ xfer->wusb_dev = wusb_dev;
+ result = urb->status;
+ if (urb->status != -EINPROGRESS)
+ goto error_dequeued;
+
+ result = __wa_xfer_setup(xfer, urb);
+ if (result < 0)
+ goto error_xfer_setup;
+ result = __wa_xfer_submit(xfer);
+ if (result < 0)
+ goto error_xfer_submit;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ d_fnend(3, dev, "(wa %p urb %p) = void\n", wa, urb);
+ return;
+
+ /* this is basically wa_xfer_completion() broken up wa_xfer_giveback()
+ * does a wa_xfer_put() that will call wa_xfer_destroy() and clean
+ * upundo setup().
+ */
+error_xfer_setup:
+error_dequeued:
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ /* FIXME: segmentation broken, kills DWA */
+ if (wusb_dev)
+ wusb_dev_put(wusb_dev);
+error_dev_gone:
+ rpipe_put(xfer->ep->hcpriv);
+error_rpipe_get:
+ xfer->result = result;
+ wa_xfer_giveback(xfer);
+ d_fnend(3, dev, "(wa %p urb %p) = (void) %d\n", wa, urb, result);
+ return;
+
+error_xfer_submit:
+ done = __wa_xfer_is_done(xfer);
+ xfer->result = result;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ d_fnend(3, dev, "(wa %p urb %p) = (void) %d\n", wa, urb, result);
+ return;
+}
+
+/*
+ * Execute the delayed transfers in the Wire Adapter @wa
+ *
+ * We need to be careful here, as dequeue() could be called in the
+ * middle. That's why we do the whole thing under the
+ * wa->xfer_list_lock. If dequeue() jumps in, it first locks urb->lock
+ * and then checks the list -- so as we would be acquiring in inverse
+ * order, we just drop the lock once we have the xfer and reacquire it
+ * later.
+ */
+void wa_urb_enqueue_run(struct work_struct *ws)
+{
+ struct wahc *wa = container_of(ws, struct wahc, xfer_work);
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_xfer *xfer, *next;
+ struct urb *urb;
+
+ d_fnstart(3, dev, "(wa %p)\n", wa);
+ spin_lock_irq(&wa->xfer_list_lock);
+ list_for_each_entry_safe(xfer, next, &wa->xfer_delayed_list,
+ list_node) {
+ list_del_init(&xfer->list_node);
+ spin_unlock_irq(&wa->xfer_list_lock);
+
+ urb = xfer->urb;
+ wa_urb_enqueue_b(xfer);
+ usb_put_urb(urb); /* taken when queuing */
+
+ spin_lock_irq(&wa->xfer_list_lock);
+ }
+ spin_unlock_irq(&wa->xfer_list_lock);
+ d_fnend(3, dev, "(wa %p) = void\n", wa);
+}
+EXPORT_SYMBOL_GPL(wa_urb_enqueue_run);
+
+/*
+ * Submit a transfer to the Wire Adapter in a delayed way
+ *
+ * The process of enqueuing involves possible sleeps() [see
+ * enqueue_b(), for the rpipe_get() and the mutex_lock()]. If we are
+ * in an atomic section, we defer the enqueue_b() call--else we call direct.
+ *
+ * @urb: We own a reference to it done by the HCI Linux USB stack that
+ * will be given up by calling usb_hcd_giveback_urb() or by
+ * returning error from this function -> ergo we don't have to
+ * refcount it.
+ */
+int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,
+ struct urb *urb, gfp_t gfp)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_xfer *xfer;
+ unsigned long my_flags;
+ unsigned cant_sleep = irqs_disabled() | in_atomic();
+
+ d_fnstart(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x)\n",
+ wa, ep, urb, urb->transfer_buffer_length, gfp);
+
+ if (urb->transfer_buffer == NULL
+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+ && urb->transfer_buffer_length != 0) {
+ dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb);
+ dump_stack();
+ }
+
+ result = -ENOMEM;
+ xfer = kzalloc(sizeof(*xfer), gfp);
+ if (xfer == NULL)
+ goto error_kmalloc;
+
+ result = -ENOENT;
+ if (urb->status != -EINPROGRESS) /* cancelled */
+ goto error_dequeued; /* before starting? */
+ wa_xfer_init(xfer);
+ xfer->wa = wa_get(wa);
+ xfer->urb = urb;
+ xfer->gfp = gfp;
+ xfer->ep = ep;
+ urb->hcpriv = xfer;
+ d_printf(2, dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n",
+ xfer, urb, urb->pipe, urb->transfer_buffer_length,
+ urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma",
+ urb->pipe & USB_DIR_IN ? "inbound" : "outbound",
+ cant_sleep ? "deferred" : "inline");
+ if (cant_sleep) {
+ usb_get_urb(urb);
+ spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
+ list_add_tail(&xfer->list_node, &wa->xfer_delayed_list);
+ spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
+ queue_work(wusbd, &wa->xfer_work);
+ } else {
+ wa_urb_enqueue_b(xfer);
+ }
+ d_fnend(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x) = 0\n",
+ wa, ep, urb, urb->transfer_buffer_length, gfp);
+ return 0;
+
+error_dequeued:
+ kfree(xfer);
+error_kmalloc:
+ d_fnend(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x) = %d\n",
+ wa, ep, urb, urb->transfer_buffer_length, gfp, result);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wa_urb_enqueue);
+
+/*
+ * Dequeue a URB and make sure uwb_hcd_giveback_urb() [completion
+ * handler] is called.
+ *
+ * Until a transfer goes successfully through wa_urb_enqueue() it
+ * needs to be dequeued with completion calling; when stuck in delayed
+ * or before wa_xfer_setup() is called, we need to do completion.
+ *
+ * not setup If there is no hcpriv yet, that means that that enqueue
+ * still had no time to set the xfer up. Because
+ * urb->status should be other than -EINPROGRESS,
+ * enqueue() will catch that and bail out.
+ *
+ * If the transfer has gone through setup, we just need to clean it
+ * up. If it has gone through submit(), we have to abort it [with an
+ * asynch request] and then make sure we cancel each segment.
+ *
+ */
+int wa_urb_dequeue(struct wahc *wa, struct urb *urb)
+{
+ struct device *dev = &wa->usb_iface->dev;
+ unsigned long flags, flags2;
+ struct wa_xfer *xfer;
+ struct wa_seg *seg;
+ struct wa_rpipe *rpipe;
+ unsigned cnt;
+ unsigned rpipe_ready = 0;
+
+ d_fnstart(3, dev, "(wa %p, urb %p)\n", wa, urb);
+
+ d_printf(1, dev, "xfer %p urb %p: aborting\n", urb->hcpriv, urb);
+ xfer = urb->hcpriv;
+ if (xfer == NULL) {
+ /* NOthing setup yet enqueue will see urb->status !=
+ * -EINPROGRESS (by hcd layer) and bail out with
+ * error, no need to do completion
+ */
+ BUG_ON(urb->status == -EINPROGRESS);
+ goto out;
+ }
+ spin_lock_irqsave(&xfer->lock, flags);
+ rpipe = xfer->ep->hcpriv;
+ /* Check the delayed list -> if there, release and complete */
+ spin_lock_irqsave(&wa->xfer_list_lock, flags2);
+ if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
+ goto dequeue_delayed;
+ spin_unlock_irqrestore(&wa->xfer_list_lock, flags2);
+ if (xfer->seg == NULL) /* still hasn't reached */
+ goto out_unlock; /* setup(), enqueue_b() completes */
+ /* Ok, the xfer is in flight already, it's been setup and submitted.*/
+ __wa_xfer_abort(xfer);
+ for (cnt = 0; cnt < xfer->segs; cnt++) {
+ seg = xfer->seg[cnt];
+ switch (seg->status) {
+ case WA_SEG_NOTREADY:
+ case WA_SEG_READY:
+ printk(KERN_ERR "xfer %p#%u: dequeue bad state %u\n",
+ xfer, cnt, seg->status);
+ WARN_ON(1);
+ break;
+ case WA_SEG_DELAYED:
+ seg->status = WA_SEG_ABORTED;
+ spin_lock_irqsave(&rpipe->seg_lock, flags2);
+ list_del(&seg->list_node);
+ xfer->segs_done++;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ spin_unlock_irqrestore(&rpipe->seg_lock, flags2);
+ break;
+ case WA_SEG_SUBMITTED:
+ seg->status = WA_SEG_ABORTED;
+ usb_unlink_urb(&seg->urb);
+ if (xfer->is_inbound == 0)
+ usb_unlink_urb(seg->dto_urb);
+ xfer->segs_done++;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ break;
+ case WA_SEG_PENDING:
+ seg->status = WA_SEG_ABORTED;
+ xfer->segs_done++;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ break;
+ case WA_SEG_DTI_PENDING:
+ usb_unlink_urb(wa->dti_urb);
+ seg->status = WA_SEG_ABORTED;
+ xfer->segs_done++;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ break;
+ case WA_SEG_DONE:
+ case WA_SEG_ERROR:
+ case WA_SEG_ABORTED:
+ break;
+ }
+ }
+ xfer->result = urb->status; /* -ENOENT or -ECONNRESET */
+ __wa_xfer_is_done(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb);
+ return 0;
+
+out_unlock:
+ spin_unlock_irqrestore(&xfer->lock, flags);
+out:
+ d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb);
+ return 0;
+
+dequeue_delayed:
+ list_del_init(&xfer->list_node);
+ spin_unlock_irqrestore(&wa->xfer_list_lock, flags2);
+ xfer->result = urb->status;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ wa_xfer_giveback(xfer);
+ usb_put_urb(urb); /* we got a ref in enqueue() */
+ d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wa_urb_dequeue);
+
+/*
+ * Translation from WA status codes (WUSB1.0 Table 8.15) to errno
+ * codes
+ *
+ * Positive errno values are internal inconsistencies and should be
+ * flagged louder. Negative are to be passed up to the user in the
+ * normal way.
+ *
+ * @status: USB WA status code -- high two bits are stripped.
+ */
+static int wa_xfer_status_to_errno(u8 status)
+{
+ int errno;
+ u8 real_status = status;
+ static int xlat[] = {
+ [WA_XFER_STATUS_SUCCESS] = 0,
+ [WA_XFER_STATUS_HALTED] = -EPIPE,
+ [WA_XFER_STATUS_DATA_BUFFER_ERROR] = -ENOBUFS,
+ [WA_XFER_STATUS_BABBLE] = -EOVERFLOW,
+ [WA_XFER_RESERVED] = EINVAL,
+ [WA_XFER_STATUS_NOT_FOUND] = 0,
+ [WA_XFER_STATUS_INSUFFICIENT_RESOURCE] = -ENOMEM,
+ [WA_XFER_STATUS_TRANSACTION_ERROR] = -EILSEQ,
+ [WA_XFER_STATUS_ABORTED] = -EINTR,
+ [WA_XFER_STATUS_RPIPE_NOT_READY] = EINVAL,
+ [WA_XFER_INVALID_FORMAT] = EINVAL,
+ [WA_XFER_UNEXPECTED_SEGMENT_NUMBER] = EINVAL,
+ [WA_XFER_STATUS_RPIPE_TYPE_MISMATCH] = EINVAL,
+ };
+ status &= 0x3f;
+
+ if (status == 0)
+ return 0;
+ if (status >= ARRAY_SIZE(xlat)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s(): BUG? "
+ "Unknown WA transfer status 0x%02x\n",
+ __func__, real_status);
+ return -EINVAL;
+ }
+ errno = xlat[status];
+ if (unlikely(errno > 0)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s(): BUG? "
+ "Inconsistent WA status: 0x%02x\n",
+ __func__, real_status);
+ errno = -errno;
+ }
+ return errno;
+}
+
+/*
+ * Process a xfer result completion message
+ *
+ * inbound transfers: need to schedule a DTI read
+ *
+ * FIXME: this functio needs to be broken up in parts
+ */
+static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+ unsigned long flags;
+ u8 seg_idx;
+ struct wa_seg *seg;
+ struct wa_rpipe *rpipe;
+ struct wa_xfer_result *xfer_result = wa->xfer_result;
+ u8 done = 0;
+ u8 usb_status;
+ unsigned rpipe_ready = 0;
+
+ d_fnstart(3, dev, "(wa %p xfer %p)\n", wa, xfer);
+ spin_lock_irqsave(&xfer->lock, flags);
+ seg_idx = xfer_result->bTransferSegment & 0x7f;
+ if (unlikely(seg_idx >= xfer->segs))
+ goto error_bad_seg;
+ seg = xfer->seg[seg_idx];
+ rpipe = xfer->ep->hcpriv;
+ usb_status = xfer_result->bTransferStatus;
+ d_printf(2, dev, "xfer %p#%u: bTransferStatus 0x%02x (seg %u)\n",
+ xfer, seg_idx, usb_status, seg->status);
+ if (seg->status == WA_SEG_ABORTED
+ || seg->status == WA_SEG_ERROR) /* already handled */
+ goto segment_aborted;
+ if (seg->status == WA_SEG_SUBMITTED) /* ops, got here */
+ seg->status = WA_SEG_PENDING; /* before wa_seg{_dto}_cb() */
+ if (seg->status != WA_SEG_PENDING) {
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p#%u: Bad segment state %u\n",
+ xfer, seg_idx, seg->status);
+ seg->status = WA_SEG_PENDING; /* workaround/"fix" it */
+ }
+ if (usb_status & 0x80) {
+ seg->result = wa_xfer_status_to_errno(usb_status);
+ dev_err(dev, "DTI: xfer %p#%u failed (0x%02x)\n",
+ xfer, seg->index, usb_status);
+ goto error_complete;
+ }
+ /* FIXME: we ignore warnings, tally them for stats */
+ if (usb_status & 0x40) /* Warning?... */
+ usb_status = 0; /* ... pass */
+ if (xfer->is_inbound) { /* IN data phase: read to buffer */
+ seg->status = WA_SEG_DTI_PENDING;
+ BUG_ON(wa->buf_in_urb->status == -EINPROGRESS);
+ if (xfer->is_dma) {
+ wa->buf_in_urb->transfer_dma =
+ xfer->urb->transfer_dma
+ + seg_idx * xfer->seg_size;
+ wa->buf_in_urb->transfer_flags
+ |= URB_NO_TRANSFER_DMA_MAP;
+ } else {
+ wa->buf_in_urb->transfer_buffer =
+ xfer->urb->transfer_buffer
+ + seg_idx * xfer->seg_size;
+ wa->buf_in_urb->transfer_flags
+ &= ~URB_NO_TRANSFER_DMA_MAP;
+ }
+ wa->buf_in_urb->transfer_buffer_length =
+ le32_to_cpu(xfer_result->dwTransferLength);
+ wa->buf_in_urb->context = seg;
+ result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC);
+ if (result < 0)
+ goto error_submit_buf_in;
+ } else {
+ /* OUT data phase, complete it -- */
+ seg->status = WA_SEG_DONE;
+ seg->result = le32_to_cpu(xfer_result->dwTransferLength);
+ xfer->segs_done++;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_is_done(xfer);
+ }
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ d_fnend(3, dev, "(wa %p xfer %p) = void\n", wa, xfer);
+ return;
+
+
+error_submit_buf_in:
+ if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "DTI: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n",
+ xfer, seg_idx, result);
+ seg->result = result;
+error_complete:
+ seg->status = WA_SEG_ERROR;
+ xfer->segs_done++;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ __wa_xfer_abort(xfer);
+ done = __wa_xfer_is_done(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ d_fnend(3, dev, "(wa %p xfer %p) = void [segment/DTI-submit error]\n",
+ wa, xfer);
+ return;
+
+
+error_bad_seg:
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ wa_urb_dequeue(wa, xfer->urb);
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p#%u: bad segment\n", xfer, seg_idx);
+ if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "DTI: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ d_fnend(3, dev, "(wa %p xfer %p) = void [bad seg]\n", wa, xfer);
+ return;
+
+
+segment_aborted:
+ /* nothing to do, as the aborter did the completion */
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ d_fnend(3, dev, "(wa %p xfer %p) = void [segment aborted]\n",
+ wa, xfer);
+ return;
+
+}
+
+/*
+ * Callback for the IN data phase
+ *
+ * If succesful transition state; otherwise, take a note of the
+ * error, mark this segment done and try completion.
+ *
+ * Note we don't access until we are sure that the transfer hasn't
+ * been cancelled (ECONNRESET, ENOENT), which could mean that
+ * seg->xfer could be already gone.
+ */
+static void wa_buf_in_cb(struct urb *urb)
+{
+ struct wa_seg *seg = urb->context;
+ struct wa_xfer *xfer = seg->xfer;
+ struct wahc *wa;
+ struct device *dev;
+ struct wa_rpipe *rpipe;
+ unsigned rpipe_ready;
+ unsigned long flags;
+ u8 done = 0;
+
+ d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status);
+ switch (urb->status) {
+ case 0:
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ rpipe = xfer->ep->hcpriv;
+ d_printf(2, dev, "xfer %p#%u: data in done (%zu bytes)\n",
+ xfer, seg->index, (size_t)urb->actual_length);
+ seg->status = WA_SEG_DONE;
+ seg->result = urb->actual_length;
+ xfer->segs_done++;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ done = __wa_xfer_is_done(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ break;
+ case -ECONNRESET: /* URB unlinked; no need to do anything */
+ case -ENOENT: /* as it was done by the who unlinked us */
+ break;
+ default: /* Other errors ... */
+ spin_lock_irqsave(&xfer->lock, flags);
+ wa = xfer->wa;
+ dev = &wa->usb_iface->dev;
+ rpipe = xfer->ep->hcpriv;
+ if (printk_ratelimit())
+ dev_err(dev, "xfer %p#%u: data in error %d\n",
+ xfer, seg->index, urb->status);
+ if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)){
+ dev_err(dev, "DTO: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ }
+ seg->status = WA_SEG_ERROR;
+ seg->result = urb->status;
+ xfer->segs_done++;
+ rpipe_ready = rpipe_avail_inc(rpipe);
+ __wa_xfer_abort(xfer);
+ done = __wa_xfer_is_done(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ }
+ d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status);
+}
+
+/*
+ * Handle an incoming transfer result buffer
+ *
+ * Given a transfer result buffer, it completes the transfer (possibly
+ * scheduling and buffer in read) and then resubmits the DTI URB for a
+ * new transfer result read.
+ *
+ *
+ * The xfer_result DTI URB state machine
+ *
+ * States: OFF | RXR (Read-Xfer-Result) | RBI (Read-Buffer-In)
+ *
+ * We start in OFF mode, the first xfer_result notification [through
+ * wa_handle_notif_xfer()] moves us to RXR by posting the DTI-URB to
+ * read.
+ *
+ * We receive a buffer -- if it is not a xfer_result, we complain and
+ * repost the DTI-URB. If it is a xfer_result then do the xfer seg
+ * request accounting. If it is an IN segment, we move to RBI and post
+ * a BUF-IN-URB to the right buffer. The BUF-IN-URB callback will
+ * repost the DTI-URB and move to RXR state. if there was no IN
+ * segment, it will repost the DTI-URB.
+ *
+ * We go back to OFF when we detect a ENOENT or ESHUTDOWN (or too many
+ * errors) in the URBs.
+ */
+static void wa_xfer_result_cb(struct urb *urb)
+{
+ int result;
+ struct wahc *wa = urb->context;
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_xfer_result *xfer_result;
+ u32 xfer_id;
+ struct wa_xfer *xfer;
+ u8 usb_status;
+
+ d_fnstart(3, dev, "(%p)\n", wa);
+ BUG_ON(wa->dti_urb != urb);
+ switch (wa->dti_urb->status) {
+ case 0:
+ /* We have a xfer result buffer; check it */
+ d_printf(2, dev, "DTI: xfer result %d bytes at %p\n",
+ urb->actual_length, urb->transfer_buffer);
+ d_dump(3, dev, urb->transfer_buffer, urb->actual_length);
+ if (wa->dti_urb->actual_length != sizeof(*xfer_result)) {
+ dev_err(dev, "DTI Error: xfer result--bad size "
+ "xfer result (%d bytes vs %zu needed)\n",
+ urb->actual_length, sizeof(*xfer_result));
+ break;
+ }
+ xfer_result = wa->xfer_result;
+ if (xfer_result->hdr.bLength != sizeof(*xfer_result)) {
+ dev_err(dev, "DTI Error: xfer result--"
+ "bad header length %u\n",
+ xfer_result->hdr.bLength);
+ break;
+ }
+ if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) {
+ dev_err(dev, "DTI Error: xfer result--"
+ "bad header type 0x%02x\n",
+ xfer_result->hdr.bNotifyType);
+ break;
+ }
+ usb_status = xfer_result->bTransferStatus & 0x3f;
+ if (usb_status == WA_XFER_STATUS_ABORTED
+ || usb_status == WA_XFER_STATUS_NOT_FOUND)
+ /* taken care of already */
+ break;
+ xfer_id = xfer_result->dwTransferID;
+ xfer = wa_xfer_get_by_id(wa, xfer_id);
+ if (xfer == NULL) {
+ /* FIXME: transaction might have been cancelled */
+ dev_err(dev, "DTI Error: xfer result--"
+ "unknown xfer 0x%08x (status 0x%02x)\n",
+ xfer_id, usb_status);
+ break;
+ }
+ wa_xfer_result_chew(wa, xfer);
+ wa_xfer_put(xfer);
+ break;
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ case -ESHUTDOWN: /* going away! */
+ dev_dbg(dev, "DTI: going down! %d\n", urb->status);
+ goto out;
+ default:
+ /* Unknown error */
+ if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "DTI: URB max acceptable errors "
+ "exceeded, resetting device\n");
+ wa_reset_all(wa);
+ goto out;
+ }
+ if (printk_ratelimit())
+ dev_err(dev, "DTI: URB error %d\n", urb->status);
+ break;
+ }
+ /* Resubmit the DTI URB */
+ result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "DTI Error: Could not submit DTI URB (%d), "
+ "resetting\n", result);
+ wa_reset_all(wa);
+ }
+out:
+ d_fnend(3, dev, "(%p) = void\n", wa);
+ return;
+}
+
+/*
+ * Transfer complete notification
+ *
+ * Called from the notif.c code. We get a notification on EP2 saying
+ * that some endpoint has some transfer result data available. We are
+ * about to read it.
+ *
+ * To speed up things, we always have a URB reading the DTI URB; we
+ * don't really set it up and start it until the first xfer complete
+ * notification arrives, which is what we do here.
+ *
+ * Follow up in wa_xfer_result_cb(), as that's where the whole state
+ * machine starts.
+ *
+ * So here we just initialize the DTI URB for reading transfer result
+ * notifications and also the buffer-in URB, for reading buffers. Then
+ * we just submit the DTI URB.
+ *
+ * @wa shall be referenced
+ */
+void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
+{
+ int result;
+ struct device *dev = &wa->usb_iface->dev;
+ struct wa_notif_xfer *notif_xfer;
+ const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
+
+ d_fnstart(4, dev, "(%p, %p)\n", wa, notif_hdr);
+ notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr);
+ BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER);
+
+ if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) {
+ /* FIXME: hardcoded limitation, adapt */
+ dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n",
+ notif_xfer->bEndpoint, dti_epd->bEndpointAddress);
+ goto error;
+ }
+ if (wa->dti_urb != NULL) /* DTI URB already started */
+ goto out;
+
+ wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (wa->dti_urb == NULL) {
+ dev_err(dev, "Can't allocate DTI URB\n");
+ goto error_dti_urb_alloc;
+ }
+ usb_fill_bulk_urb(
+ wa->dti_urb, wa->usb_dev,
+ usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint),
+ wa->xfer_result, wa->xfer_result_size,
+ wa_xfer_result_cb, wa);
+
+ wa->buf_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (wa->buf_in_urb == NULL) {
+ dev_err(dev, "Can't allocate BUF-IN URB\n");
+ goto error_buf_in_urb_alloc;
+ }
+ usb_fill_bulk_urb(
+ wa->buf_in_urb, wa->usb_dev,
+ usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint),
+ NULL, 0, wa_buf_in_cb, wa);
+ result = usb_submit_urb(wa->dti_urb, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "DTI Error: Could not submit DTI URB (%d), "
+ "resetting\n", result);
+ goto error_dti_urb_submit;
+ }
+out:
+ d_fnend(4, dev, "(%p, %p) = void\n", wa, notif_hdr);
+ return;
+
+error_dti_urb_submit:
+ usb_put_urb(wa->buf_in_urb);
+error_buf_in_urb_alloc:
+ usb_put_urb(wa->dti_urb);
+ wa->dti_urb = NULL;
+error_dti_urb_alloc:
+error:
+ wa_reset_all(wa);
+ d_fnend(4, dev, "(%p, %p) = void\n", wa, notif_hdr);
+ return;
+}
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c
new file mode 100644
index 00000000000..07c63a31c79
--- /dev/null
+++ b/drivers/usb/wusbcore/wusbhc.c
@@ -0,0 +1,418 @@
+/*
+ * Wireless USB Host Controller
+ * sysfs glue, wusbcore module support and life cycle management
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * Creation/destruction of wusbhc is split in two parts; that that
+ * doesn't require the HCD to be added (wusbhc_{create,destroy}) and
+ * the one that requires (phase B, wusbhc_b_{create,destroy}).
+ *
+ * This is so because usb_add_hcd() will start the HC, and thus, all
+ * the HC specific stuff has to be already initialiazed (like sysfs
+ * thingies).
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include "wusbhc.h"
+
+/**
+ * Extract the wusbhc that corresponds to a USB Host Controller class device
+ *
+ * WARNING! Apply only if @dev is that of a
+ * wusbhc.usb_hcd.self->class_dev; otherwise, you loose.
+ */
+static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev)
+{
+ struct usb_bus *usb_bus = dev_get_drvdata(dev);
+ struct usb_hcd *usb_hcd = bus_to_hcd(usb_bus);
+ return usb_hcd_to_wusbhc(usb_hcd);
+}
+
+/*
+ * Show & store the current WUSB trust timeout
+ *
+ * We don't do locking--it is an 'atomic' value.
+ *
+ * The units that we store/show are always MILLISECONDS. However, the
+ * value of trust_timeout is jiffies.
+ */
+static ssize_t wusb_trust_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", wusbhc->trust_timeout);
+}
+
+static ssize_t wusb_trust_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ ssize_t result = -ENOSYS;
+ unsigned trust_timeout;
+
+ result = sscanf(buf, "%u", &trust_timeout);
+ if (result != 1) {
+ result = -EINVAL;
+ goto out;
+ }
+ /* FIXME: maybe we should check for range validity? */
+ wusbhc->trust_timeout = trust_timeout;
+ cancel_delayed_work(&wusbhc->keep_alive_timer);
+ flush_workqueue(wusbd);
+ queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
+ (trust_timeout * CONFIG_HZ)/1000/2);
+out:
+ return result < 0 ? result : size;
+}
+static DEVICE_ATTR(wusb_trust_timeout, 0644, wusb_trust_timeout_show,
+ wusb_trust_timeout_store);
+
+/*
+ * Show & store the current WUSB CHID
+ */
+static ssize_t wusb_chid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ ssize_t result = 0;
+
+ if (wusbhc->wuie_host_info != NULL)
+ result += ckhdid_printf(buf, PAGE_SIZE,
+ &wusbhc->wuie_host_info->CHID);
+ return result;
+}
+
+/*
+ * Store a new CHID
+ *
+ * This will (FIXME) trigger many changes.
+ *
+ * - Send an all zeros CHID and it will stop the controller
+ * - Send a non-zero CHID and it will start it
+ * (unless it was started, it will just change the CHID,
+ * diconnecting all devices first).
+ *
+ * So first we scan the MMC we are sent and then we act on it. We
+ * read it in the same format as we print it, an ASCII string of 16
+ * hex bytes.
+ *
+ * See wusbhc_chid_set() for more info.
+ */
+static ssize_t wusb_chid_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ struct wusb_ckhdid chid;
+ ssize_t result;
+
+ result = sscanf(buf,
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx\n",
+ &chid.data[0] , &chid.data[1] ,
+ &chid.data[2] , &chid.data[3] ,
+ &chid.data[4] , &chid.data[5] ,
+ &chid.data[6] , &chid.data[7] ,
+ &chid.data[8] , &chid.data[9] ,
+ &chid.data[10], &chid.data[11],
+ &chid.data[12], &chid.data[13],
+ &chid.data[14], &chid.data[15]);
+ if (result != 16) {
+ dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits): "
+ "%d\n", (int)result);
+ return -EINVAL;
+ }
+ result = wusbhc_chid_set(wusbhc, &chid);
+ return result < 0 ? result : size;
+}
+static DEVICE_ATTR(wusb_chid, 0644, wusb_chid_show, wusb_chid_store);
+
+/* Group all the WUSBHC attributes */
+static struct attribute *wusbhc_attrs[] = {
+ &dev_attr_wusb_trust_timeout.attr,
+ &dev_attr_wusb_chid.attr,
+ NULL,
+};
+
+static struct attribute_group wusbhc_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = wusbhc_attrs,
+};
+
+/*
+ * Create a wusbhc instance
+ *
+ * NOTEs:
+ *
+ * - assumes *wusbhc has been zeroed and wusbhc->usb_hcd has been
+ * initialized but not added.
+ *
+ * - fill out ports_max, mmcies_max and mmcie_{add,rm} before calling.
+ *
+ * - fill out wusbhc->uwb_rc and refcount it before calling
+ * - fill out the wusbhc->sec_modes array
+ */
+int wusbhc_create(struct wusbhc *wusbhc)
+{
+ int result = 0;
+
+ wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS;
+ mutex_init(&wusbhc->mutex);
+ result = wusbhc_mmcie_create(wusbhc);
+ if (result < 0)
+ goto error_mmcie_create;
+ result = wusbhc_devconnect_create(wusbhc);
+ if (result < 0)
+ goto error_devconnect_create;
+ result = wusbhc_rh_create(wusbhc);
+ if (result < 0)
+ goto error_rh_create;
+ result = wusbhc_sec_create(wusbhc);
+ if (result < 0)
+ goto error_sec_create;
+ return 0;
+
+error_sec_create:
+ wusbhc_rh_destroy(wusbhc);
+error_rh_create:
+ wusbhc_devconnect_destroy(wusbhc);
+error_devconnect_create:
+ wusbhc_mmcie_destroy(wusbhc);
+error_mmcie_create:
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_create);
+
+static inline struct kobject *wusbhc_kobj(struct wusbhc *wusbhc)
+{
+ return &wusbhc->usb_hcd.self.controller->kobj;
+}
+
+/*
+ * Phase B of a wusbhc instance creation
+ *
+ * Creates fields that depend on wusbhc->usb_hcd having been
+ * added. This is where we create the sysfs files in
+ * /sys/class/usb_host/usb_hostX/.
+ *
+ * NOTE: Assumes wusbhc->usb_hcd has been already added by the upper
+ * layer (hwahc or whci)
+ */
+int wusbhc_b_create(struct wusbhc *wusbhc)
+{
+ int result = 0;
+ struct device *dev = wusbhc->usb_hcd.self.controller;
+
+ result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
+ if (result < 0) {
+ dev_err(dev, "Cannot register WUSBHC attributes: %d\n", result);
+ goto error_create_attr_group;
+ }
+
+ result = wusbhc_pal_register(wusbhc);
+ if (result < 0)
+ goto error_pal_register;
+ return 0;
+
+error_pal_register:
+ sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
+error_create_attr_group:
+ return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_b_create);
+
+void wusbhc_b_destroy(struct wusbhc *wusbhc)
+{
+ wusbhc_pal_unregister(wusbhc);
+ sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
+}
+EXPORT_SYMBOL_GPL(wusbhc_b_destroy);
+
+void wusbhc_destroy(struct wusbhc *wusbhc)
+{
+ wusbhc_sec_destroy(wusbhc);
+ wusbhc_rh_destroy(wusbhc);
+ wusbhc_devconnect_destroy(wusbhc);
+ wusbhc_mmcie_destroy(wusbhc);
+}
+EXPORT_SYMBOL_GPL(wusbhc_destroy);
+
+struct workqueue_struct *wusbd;
+EXPORT_SYMBOL_GPL(wusbd);
+
+/*
+ * WUSB Cluster ID allocation map
+ *
+ * Each WUSB bus in a channel is identified with a Cluster Id in the
+ * unauth address pace (WUSB1.0[4.3]). We take the range 0xe0 to 0xff
+ * (that's space for 31 WUSB controllers, as 0xff can't be taken). We
+ * start taking from 0xff, 0xfe, 0xfd... (hence the += or -= 0xff).
+ *
+ * For each one we taken, we pin it in the bitap
+ */
+#define CLUSTER_IDS 32
+static DECLARE_BITMAP(wusb_cluster_id_table, CLUSTER_IDS);
+static DEFINE_SPINLOCK(wusb_cluster_ids_lock);
+
+/*
+ * Get a WUSB Cluster ID
+ *
+ * Need to release with wusb_cluster_id_put() when done w/ it.
+ */
+/* FIXME: coordinate with the choose_addres() from the USB stack */
+/* we want to leave the top of the 128 range for cluster addresses and
+ * the bottom for device addresses (as we map them one on one with
+ * ports). */
+u8 wusb_cluster_id_get(void)
+{
+ u8 id;
+ spin_lock(&wusb_cluster_ids_lock);
+ id = find_first_zero_bit(wusb_cluster_id_table, CLUSTER_IDS);
+ if (id > CLUSTER_IDS) {
+ id = 0;
+ goto out;
+ }
+ set_bit(id, wusb_cluster_id_table);
+ id = (u8) 0xff - id;
+out:
+ spin_unlock(&wusb_cluster_ids_lock);
+ return id;
+
+}
+EXPORT_SYMBOL_GPL(wusb_cluster_id_get);
+
+/*
+ * Release a WUSB Cluster ID
+ *
+ * Obtained it with wusb_cluster_id_get()
+ */
+void wusb_cluster_id_put(u8 id)
+{
+ id = 0xff - id;
+ BUG_ON(id >= CLUSTER_IDS);
+ spin_lock(&wusb_cluster_ids_lock);
+ WARN_ON(!test_bit(id, wusb_cluster_id_table));
+ clear_bit(id, wusb_cluster_id_table);
+ spin_unlock(&wusb_cluster_ids_lock);
+}
+EXPORT_SYMBOL_GPL(wusb_cluster_id_put);
+
+/**
+ * wusbhc_giveback_urb - return an URB to the USB core
+ * @wusbhc: the host controller the URB is from.
+ * @urb: the URB.
+ * @status: the URB's status.
+ *
+ * Return an URB to the USB core doing some additional WUSB specific
+ * processing.
+ *
+ * - After a successful transfer, update the trust timeout timestamp
+ * for the WUSB device.
+ *
+ * - [WUSB] sections 4.13 and 7.5.1 specifies the stop retrasmittion
+ * condition for the WCONNECTACK_IE is that the host has observed
+ * the associated device responding to a control transfer.
+ */
+void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status)
+{
+ struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev);
+
+ if (status == 0) {
+ wusb_dev->entry_ts = jiffies;
+
+ /* wusbhc_devconnect_acked() can't be called from from
+ atomic context so defer it to a work queue. */
+ if (!list_empty(&wusb_dev->cack_node))
+ queue_work(wusbd, &wusb_dev->devconnect_acked_work);
+ }
+
+ usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status);
+}
+EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);
+
+/**
+ * wusbhc_reset_all - reset the HC hardware
+ * @wusbhc: the host controller to reset.
+ *
+ * Request a full hardware reset of the chip. This will also reset
+ * the radio controller and any other PALs.
+ */
+void wusbhc_reset_all(struct wusbhc *wusbhc)
+{
+ uwb_rc_reset_all(wusbhc->uwb_rc);
+}
+EXPORT_SYMBOL_GPL(wusbhc_reset_all);
+
+static struct notifier_block wusb_usb_notifier = {
+ .notifier_call = wusb_usb_ncb,
+ .priority = INT_MAX /* Need to be called first of all */
+};
+
+static int __init wusbcore_init(void)
+{
+ int result;
+ result = wusb_crypto_init();
+ if (result < 0)
+ goto error_crypto_init;
+ /* WQ is singlethread because we need to serialize notifications */
+ wusbd = create_singlethread_workqueue("wusbd");
+ if (wusbd == NULL) {
+ result = -ENOMEM;
+ printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n");
+ goto error_wusbd_create;
+ }
+ usb_register_notify(&wusb_usb_notifier);
+ bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS);
+ set_bit(0, wusb_cluster_id_table); /* reserve Cluster ID 0xff */
+ return 0;
+
+error_wusbd_create:
+ wusb_crypto_exit();
+error_crypto_init:
+ return result;
+
+}
+module_init(wusbcore_init);
+
+static void __exit wusbcore_exit(void)
+{
+ clear_bit(0, wusb_cluster_id_table);
+ if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) {
+ char buf[256];
+ bitmap_scnprintf(buf, sizeof(buf), wusb_cluster_id_table,
+ CLUSTER_IDS);
+ printk(KERN_ERR "BUG: WUSB Cluster IDs not released "
+ "on exit: %s\n", buf);
+ WARN_ON(1);
+ }
+ usb_unregister_notify(&wusb_usb_notifier);
+ destroy_workqueue(wusbd);
+ wusb_crypto_exit();
+}
+module_exit(wusbcore_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless USB core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h
new file mode 100644
index 00000000000..d0c132434f1
--- /dev/null
+++ b/drivers/usb/wusbcore/wusbhc.h
@@ -0,0 +1,495 @@
+/*
+ * Wireless USB Host Controller
+ * Common infrastructure for WHCI and HWA WUSB-HC drivers
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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 driver implements parts common to all Wireless USB Host
+ * Controllers (struct wusbhc, embedding a struct usb_hcd) and is used
+ * by:
+ *
+ * - hwahc: HWA, USB-dongle that implements a Wireless USB host
+ * controller, (Wireless USB 1.0 Host-Wire-Adapter specification).
+ *
+ * - whci: WHCI, a PCI card with a wireless host controller
+ * (Wireless Host Controller Interface 1.0 specification).
+ *
+ * Check out the Design-overview.txt file in the source documentation
+ * for other details on the implementation.
+ *
+ * Main blocks:
+ *
+ * rh Root Hub emulation (part of the HCD glue)
+ *
+ * devconnect Handle all the issues related to device connection,
+ * authentication, disconnection, timeout, reseting,
+ * keepalives, etc.
+ *
+ * mmc MMC IE broadcasting handling
+ *
+ * A host controller driver just initializes its stuff and as part of
+ * that, creates a 'struct wusbhc' instance that handles all the
+ * common WUSB mechanisms. Links in the function ops that are specific
+ * to it and then registers the host controller. Ready to run.
+ */
+
+#ifndef __WUSBHC_H__
+#define __WUSBHC_H__
+
+#include <linux/usb.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/kref.h>
+#include <linux/workqueue.h>
+/* FIXME: Yes, I know: BAD--it's not my fault the USB HC iface is not
+ * public */
+#include <linux/../../drivers/usb/core/hcd.h>
+#include <linux/uwb.h>
+#include <linux/usb/wusb.h>
+
+
+/**
+ * Wireless USB device
+ *
+ * Describe a WUSB device connected to the cluster. This struct
+ * belongs to the 'struct wusb_port' it is attached to and it is
+ * responsible for putting and clearing the pointer to it.
+ *
+ * Note this "complements" the 'struct usb_device' that the usb_hcd
+ * keeps for each connected USB device. However, it extends some
+ * information that is not available (there is no hcpriv ptr in it!)
+ * *and* most importantly, it's life cycle is different. It is created
+ * as soon as we get a DN_Connect (connect request notification) from
+ * the device through the WUSB host controller; the USB stack doesn't
+ * create the device until we authenticate it. FIXME: this will
+ * change.
+ *
+ * @bos: This is allocated when the BOS descriptors are read from
+ * the device and freed upon the wusb_dev struct dying.
+ * @wusb_cap_descr: points into @bos, and has been verified to be size
+ * safe.
+ */
+struct wusb_dev {
+ struct kref refcnt;
+ struct wusbhc *wusbhc;
+ struct list_head cack_node; /* Connect-Ack list */
+ u8 port_idx;
+ u8 addr;
+ u8 beacon_type:4;
+ struct usb_encryption_descriptor ccm1_etd;
+ struct wusb_ckhdid cdid;
+ unsigned long entry_ts;
+ struct usb_bos_descriptor *bos;
+ struct usb_wireless_cap_descriptor *wusb_cap_descr;
+ struct uwb_mas_bm availability;
+ struct work_struct devconnect_acked_work;
+ struct urb *set_gtk_urb;
+ struct usb_ctrlrequest *set_gtk_req;
+ struct usb_device *usb_dev;
+};
+
+#define WUSB_DEV_ADDR_UNAUTH 0x80
+
+static inline void wusb_dev_init(struct wusb_dev *wusb_dev)
+{
+ kref_init(&wusb_dev->refcnt);
+ /* no need to init the cack_node */
+}
+
+extern void wusb_dev_destroy(struct kref *_wusb_dev);
+
+static inline struct wusb_dev *wusb_dev_get(struct wusb_dev *wusb_dev)
+{
+ kref_get(&wusb_dev->refcnt);
+ return wusb_dev;
+}
+
+static inline void wusb_dev_put(struct wusb_dev *wusb_dev)
+{
+ kref_put(&wusb_dev->refcnt, wusb_dev_destroy);
+}
+
+/**
+ * Wireless USB Host Controlller root hub "fake" ports
+ * (state and device information)
+ *
+ * Wireless USB is wireless, so there are no ports; but we
+ * fake'em. Each RC can connect a max of devices at the same time
+ * (given in the Wireless Adapter descriptor, bNumPorts or WHCI's
+ * caps), referred to in wusbhc->ports_max.
+ *
+ * See rh.c for more information.
+ *
+ * The @status and @change use the same bits as in USB2.0[11.24.2.7],
+ * so we don't have to do much when getting the port's status.
+ *
+ * WUSB1.0[7.1], USB2.0[11.24.2.7.1,fig 11-10],
+ * include/linux/usb_ch9.h (#define USB_PORT_STAT_*)
+ */
+struct wusb_port {
+ u16 status;
+ u16 change;
+ struct wusb_dev *wusb_dev; /* connected device's info */
+ unsigned reset_count;
+ u32 ptk_tkid;
+};
+
+/**
+ * WUSB Host Controller specifics
+ *
+ * All fields that are common to all Wireless USB controller types
+ * (HWA and WHCI) are grouped here. Host Controller
+ * functions/operations that only deal with general Wireless USB HC
+ * issues use this data type to refer to the host.
+ *
+ * @usb_hcd Instantiation of a USB host controller
+ * (initialized by upper layer [HWA=HC or WHCI].
+ *
+ * @dev Device that implements this; initialized by the
+ * upper layer (HWA-HC, WHCI...); this device should
+ * have a refcount.
+ *
+ * @trust_timeout After this time without hearing for device
+ * activity, we consider the device gone and we have to
+ * re-authenticate.
+ *
+ * Can be accessed w/o locking--however, read to a
+ * local variable then use.
+ *
+ * @chid WUSB Cluster Host ID: this is supposed to be a
+ * unique value that doesn't change across reboots (so
+ * that your devices do not require re-association).
+ *
+ * Read/Write protected by @mutex
+ *
+ * @dev_info This array has ports_max elements. It is used to
+ * give the HC information about the WUSB devices (see
+ * 'struct wusb_dev_info').
+ *
+ * For HWA we need to allocate it in heap; for WHCI it
+ * needs to be permanently mapped, so we keep it for
+ * both and make it easy. Call wusbhc->dev_info_set()
+ * to update an entry.
+ *
+ * @ports_max Number of simultaneous device connections (fake
+ * ports) this HC will take. Read-only.
+ *
+ * @port Array of port status for each fake root port. Guaranteed to
+ * always be the same lenght during device existence
+ * [this allows for some unlocked but referenced reading].
+ *
+ * @mmcies_max Max number of Information Elements this HC can send
+ * in its MMC. Read-only.
+ *
+ * @mmcie_add HC specific operation (WHCI or HWA) for adding an
+ * MMCIE.
+ *
+ * @mmcie_rm HC specific operation (WHCI or HWA) for removing an
+ * MMCIE.
+ *
+ * @enc_types Array which describes the encryptions methods
+ * supported by the host as described in WUSB1.0 --
+ * one entry per supported method. As of WUSB1.0 there
+ * is only four methods, we make space for eight just in
+ * case they decide to add some more (and pray they do
+ * it in sequential order). if 'enc_types[enc_method]
+ * != 0', then it is supported by the host. enc_method
+ * is USB_ENC_TYPE*.
+ *
+ * @set_ptk: Set the PTK and enable encryption for a device. Or, if
+ * the supplied key is NULL, disable encryption for that
+ * device.
+ *
+ * @set_gtk: Set the GTK to be used for all future broadcast packets
+ * (i.e., MMCs). With some hardware, setting the GTK may start
+ * MMC transmission.
+ *
+ * NOTE:
+ *
+ * - If wusb_dev->usb_dev is not NULL, then usb_dev is valid
+ * (wusb_dev has a refcount on it). Likewise, if usb_dev->wusb_dev
+ * is not NULL, usb_dev->wusb_dev is valid (usb_dev keeps a
+ * refcount on it).
+ *
+ * Most of the times when you need to use it, it will be non-NULL,
+ * so there is no real need to check for it (wusb_dev will
+ * dissapear before usb_dev).
+ *
+ * - The following fields need to be filled out before calling
+ * wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}.
+ *
+ * - there is no wusbhc_init() method, we do everything in
+ * wusbhc_create().
+ *
+ * - Creation is done in two phases, wusbhc_create() and
+ * wusbhc_create_b(); b are the parts that need to be called after
+ * calling usb_hcd_add(&wusbhc->usb_hcd).
+ */
+struct wusbhc {
+ struct usb_hcd usb_hcd; /* HAS TO BE 1st */
+ struct device *dev;
+ struct uwb_rc *uwb_rc;
+ struct uwb_pal pal;
+
+ unsigned trust_timeout; /* in jiffies */
+ struct wuie_host_info *wuie_host_info; /* Includes CHID */
+
+ struct mutex mutex; /* locks everything else */
+ u16 cluster_id; /* Wireless USB Cluster ID */
+ struct wusb_port *port; /* Fake port status handling */
+ struct wusb_dev_info *dev_info; /* for Set Device Info mgmt */
+ u8 ports_max;
+ unsigned active:1; /* currently xmit'ing MMCs */
+ struct wuie_keep_alive keep_alive_ie; /* protected by mutex */
+ struct delayed_work keep_alive_timer;
+ struct list_head cack_list; /* Connect acknowledging */
+ size_t cack_count; /* protected by 'mutex' */
+ struct wuie_connect_ack cack_ie;
+ struct uwb_rsv *rsv; /* cluster bandwidth reservation */
+
+ struct mutex mmcie_mutex; /* MMC WUIE handling */
+ struct wuie_hdr **mmcie; /* WUIE array */
+ u8 mmcies_max;
+ /* FIXME: make wusbhc_ops? */
+ int (*start)(struct wusbhc *wusbhc);
+ void (*stop)(struct wusbhc *wusbhc);
+ int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+ u8 handle, struct wuie_hdr *wuie);
+ int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle);
+ int (*dev_info_set)(struct wusbhc *, struct wusb_dev *wusb_dev);
+ int (*bwa_set)(struct wusbhc *wusbhc, s8 stream_index,
+ const struct uwb_mas_bm *);
+ int (*set_ptk)(struct wusbhc *wusbhc, u8 port_idx,
+ u32 tkid, const void *key, size_t key_size);
+ int (*set_gtk)(struct wusbhc *wusbhc,
+ u32 tkid, const void *key, size_t key_size);
+ int (*set_num_dnts)(struct wusbhc *wusbhc, u8 interval, u8 slots);
+
+ struct {
+ struct usb_key_descriptor descr;
+ u8 data[16]; /* GTK key data */
+ } __attribute__((packed)) gtk;
+ u8 gtk_index;
+ u32 gtk_tkid;
+ struct work_struct gtk_rekey_done_work;
+ int pending_set_gtks;
+
+ struct usb_encryption_descriptor *ccm1_etd;
+};
+
+#define usb_hcd_to_wusbhc(u) container_of((u), struct wusbhc, usb_hcd)
+
+
+extern int wusbhc_create(struct wusbhc *);
+extern int wusbhc_b_create(struct wusbhc *);
+extern void wusbhc_b_destroy(struct wusbhc *);
+extern void wusbhc_destroy(struct wusbhc *);
+extern int wusb_dev_sysfs_add(struct wusbhc *, struct usb_device *,
+ struct wusb_dev *);
+extern void wusb_dev_sysfs_rm(struct wusb_dev *);
+extern int wusbhc_sec_create(struct wusbhc *);
+extern int wusbhc_sec_start(struct wusbhc *);
+extern void wusbhc_sec_stop(struct wusbhc *);
+extern void wusbhc_sec_destroy(struct wusbhc *);
+extern void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb,
+ int status);
+void wusbhc_reset_all(struct wusbhc *wusbhc);
+
+int wusbhc_pal_register(struct wusbhc *wusbhc);
+void wusbhc_pal_unregister(struct wusbhc *wusbhc);
+
+/*
+ * Return @usb_dev's @usb_hcd (properly referenced) or NULL if gone
+ *
+ * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
+ *
+ * This is a safe assumption as @usb_dev->bus is referenced all the
+ * time during the @usb_dev life cycle.
+ */
+static inline struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev)
+{
+ struct usb_hcd *usb_hcd;
+ usb_hcd = container_of(usb_dev->bus, struct usb_hcd, self);
+ return usb_get_hcd(usb_hcd);
+}
+
+/*
+ * Increment the reference count on a wusbhc.
+ *
+ * @wusbhc's life cycle is identical to that of the underlying usb_hcd.
+ */
+static inline struct wusbhc *wusbhc_get(struct wusbhc *wusbhc)
+{
+ return usb_get_hcd(&wusbhc->usb_hcd) ? wusbhc : NULL;
+}
+
+/*
+ * Return the wusbhc associated to a @usb_dev
+ *
+ * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
+ *
+ * @returns: wusbhc for @usb_dev; NULL if the @usb_dev is being torn down.
+ * WARNING: referenced at the usb_hcd level, unlocked
+ *
+ * FIXME: move offline
+ */
+static inline struct wusbhc *wusbhc_get_by_usb_dev(struct usb_device *usb_dev)
+{
+ struct wusbhc *wusbhc = NULL;
+ struct usb_hcd *usb_hcd;
+ if (usb_dev->devnum > 1 && !usb_dev->wusb) {
+ /* but root hubs */
+ dev_err(&usb_dev->dev, "devnum %d wusb %d\n", usb_dev->devnum,
+ usb_dev->wusb);
+ BUG_ON(usb_dev->devnum > 1 && !usb_dev->wusb);
+ }
+ usb_hcd = usb_hcd_get_by_usb_dev(usb_dev);
+ if (usb_hcd == NULL)
+ return NULL;
+ BUG_ON(usb_hcd->wireless == 0);
+ return wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+}
+
+
+static inline void wusbhc_put(struct wusbhc *wusbhc)
+{
+ usb_put_hcd(&wusbhc->usb_hcd);
+}
+
+int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid);
+void wusbhc_stop(struct wusbhc *wusbhc);
+extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *);
+
+/* Device connect handling */
+extern int wusbhc_devconnect_create(struct wusbhc *);
+extern void wusbhc_devconnect_destroy(struct wusbhc *);
+extern int wusbhc_devconnect_start(struct wusbhc *wusbhc,
+ const struct wusb_ckhdid *chid);
+extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc);
+extern int wusbhc_devconnect_auth(struct wusbhc *, u8);
+extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr,
+ struct wusb_dn_hdr *dn_hdr, size_t size);
+extern int wusbhc_dev_reset(struct wusbhc *wusbhc, u8 port);
+extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port);
+extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
+ void *priv);
+extern int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
+ u8 addr);
+
+/* Wireless USB fake Root Hub methods */
+extern int wusbhc_rh_create(struct wusbhc *);
+extern void wusbhc_rh_destroy(struct wusbhc *);
+
+extern int wusbhc_rh_status_data(struct usb_hcd *, char *);
+extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16);
+extern int wusbhc_rh_suspend(struct usb_hcd *);
+extern int wusbhc_rh_resume(struct usb_hcd *);
+extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned);
+
+/* MMC handling */
+extern int wusbhc_mmcie_create(struct wusbhc *);
+extern void wusbhc_mmcie_destroy(struct wusbhc *);
+extern int wusbhc_mmcie_set(struct wusbhc *, u8 interval, u8 repeat_cnt,
+ struct wuie_hdr *);
+extern void wusbhc_mmcie_rm(struct wusbhc *, struct wuie_hdr *);
+
+/* Bandwidth reservation */
+int wusbhc_rsv_establish(struct wusbhc *wusbhc);
+void wusbhc_rsv_terminate(struct wusbhc *wusbhc);
+
+/*
+ * I've always said
+ * I wanted a wedding in a church...
+ *
+ * but lately I've been thinking about
+ * the Botanical Gardens.
+ *
+ * We could do it by the tulips.
+ * It'll be beautiful
+ *
+ * --Security!
+ */
+extern int wusb_dev_sec_add(struct wusbhc *, struct usb_device *,
+ struct wusb_dev *);
+extern void wusb_dev_sec_rm(struct wusb_dev *) ;
+extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *,
+ struct wusb_ckhdid *ck);
+void wusbhc_gtk_rekey(struct wusbhc *wusbhc);
+
+
+/* WUSB Cluster ID handling */
+extern u8 wusb_cluster_id_get(void);
+extern void wusb_cluster_id_put(u8);
+
+/*
+ * wusb_port_by_idx - return the port associated to a zero-based port index
+ *
+ * NOTE: valid without locking as long as wusbhc is referenced (as the
+ * number of ports doesn't change). The data pointed to has to
+ * be verified though :)
+ */
+static inline struct wusb_port *wusb_port_by_idx(struct wusbhc *wusbhc,
+ u8 port_idx)
+{
+ return &wusbhc->port[port_idx];
+}
+
+/*
+ * wusb_port_no_to_idx - Convert port number (per usb_dev->portnum) to
+ * a port_idx.
+ *
+ * USB stack USB ports are 1 based!!
+ *
+ * NOTE: only valid for WUSB devices!!!
+ */
+static inline u8 wusb_port_no_to_idx(u8 port_no)
+{
+ return port_no - 1;
+}
+
+extern struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *,
+ struct usb_device *);
+
+/*
+ * Return a referenced wusb_dev given a @usb_dev
+ *
+ * Returns NULL if the usb_dev is being torn down.
+ *
+ * FIXME: move offline
+ */
+static inline
+struct wusb_dev *wusb_dev_get_by_usb_dev(struct usb_device *usb_dev)
+{
+ struct wusbhc *wusbhc;
+ struct wusb_dev *wusb_dev;
+ wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+ if (wusbhc == NULL)
+ return NULL;
+ mutex_lock(&wusbhc->mutex);
+ wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
+ mutex_unlock(&wusbhc->mutex);
+ wusbhc_put(wusbhc);
+ return wusb_dev;
+}
+
+/* Misc */
+
+extern struct workqueue_struct *wusbd;
+#endif /* #ifndef __WUSBHC_H__ */
diff --git a/drivers/uwb/Kconfig b/drivers/uwb/Kconfig
new file mode 100644
index 00000000000..ca783127af3
--- /dev/null
+++ b/drivers/uwb/Kconfig
@@ -0,0 +1,90 @@
+#
+# UWB device configuration
+#
+
+menuconfig UWB
+ tristate "Ultra Wideband devices (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on PCI
+ default n
+ help
+ UWB is a high-bandwidth, low-power, point-to-point radio
+ technology using a wide spectrum (3.1-10.6GHz). It is
+ optimized for in-room use (480Mbps at 2 meters, 110Mbps at
+ 10m). It serves as the transport layer for other protocols,
+ such as Wireless USB (WUSB), IP (WLP) and upcoming
+ Bluetooth and 1394
+
+ The topology is peer to peer; however, higher level
+ protocols (such as WUSB) might impose a master/slave
+ relationship.
+
+ Say Y here if your computer has UWB radio controllers (USB or PCI)
+ based. You will need to enable the radio controllers
+ below. It is ok to select all of them, no harm done.
+
+ For more help check the UWB and WUSB related files in
+ <file:Documentation/usb/>.
+
+ To compile the UWB stack as a module, choose M here.
+
+if UWB
+
+config UWB_HWA
+ tristate "UWB Radio Control driver for WUSB-compliant USB dongles (HWA)"
+ depends on USB
+ help
+ This driver enables the radio controller for HWA USB
+ devices. HWA stands for Host Wire Adapter, and it is a UWB
+ Radio Controller connected to your system via USB. Most of
+ them come with a Wireless USB host controller also.
+
+ To compile this driver select Y (built in) or M (module). It
+ is safe to select any even if you do not have the hardware.
+
+config UWB_WHCI
+ tristate "UWB Radio Control driver for WHCI-compliant cards"
+ depends on PCI
+ help
+ This driver enables the radio controller for WHCI cards.
+
+ WHCI is an specification developed by Intel
+ (http://www.intel.com/technology/comms/wusb/whci.htm) much
+ in the spirit of USB's EHCI, but for UWB and Wireless USB
+ radio/host controllers connected via memmory mapping (eg:
+ PCI). Most of these cards come also with a Wireless USB host
+ controller.
+
+ To compile this driver select Y (built in) or M (module). It
+ is safe to select any even if you do not have the hardware.
+
+config UWB_WLP
+ tristate "Support WiMedia Link Protocol (Ethernet/IP over UWB)"
+ depends on UWB && NET
+ help
+ This is a common library for drivers that implement
+ networking over UWB.
+
+config UWB_I1480U
+ tristate "Support for Intel Wireless UWB Link 1480 HWA"
+ depends on UWB_HWA
+ select FW_LOADER
+ help
+ This driver enables support for the i1480 when connected via
+ USB. It consists of a firmware uploader that will enable it
+ to behave as an HWA device.
+
+ To compile this driver select Y (built in) or M (module). It
+ is safe to select any even if you do not have the hardware.
+
+config UWB_I1480U_WLP
+ tristate "Support for Intel Wireless UWB Link 1480 HWA's WLP interface"
+ depends on UWB_I1480U && UWB_WLP && NET
+ help
+ This driver enables WLP support for the i1480 when connected via
+ USB. WLP is the WiMedia Link Protocol, or IP over UWB.
+
+ To compile this driver select Y (built in) or M (module). It
+ is safe to select any even if you don't have the hardware.
+
+endif # UWB
diff --git a/drivers/uwb/Makefile b/drivers/uwb/Makefile
new file mode 100644
index 00000000000..257e6908304
--- /dev/null
+++ b/drivers/uwb/Makefile
@@ -0,0 +1,29 @@
+obj-$(CONFIG_UWB) += uwb.o
+obj-$(CONFIG_UWB_WLP) += wlp/
+obj-$(CONFIG_UWB_WHCI) += umc.o whci.o whc-rc.o
+obj-$(CONFIG_UWB_HWA) += hwa-rc.o
+obj-$(CONFIG_UWB_I1480U) += i1480/
+
+uwb-objs := \
+ address.o \
+ beacon.o \
+ driver.o \
+ drp.o \
+ drp-avail.o \
+ drp-ie.o \
+ est.o \
+ ie.o \
+ lc-dev.o \
+ lc-rc.o \
+ neh.o \
+ pal.o \
+ reset.o \
+ rsv.o \
+ scan.o \
+ uwb-debug.o \
+ uwbd.o
+
+umc-objs := \
+ umc-bus.o \
+ umc-dev.o \
+ umc-drv.o
diff --git a/drivers/uwb/address.c b/drivers/uwb/address.c
new file mode 100644
index 00000000000..1664ae5f170
--- /dev/null
+++ b/drivers/uwb/address.c
@@ -0,0 +1,374 @@
+/*
+ * Ultra Wide Band
+ * Address management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/random.h>
+#include <linux/etherdevice.h>
+#include <linux/uwb/debug.h>
+#include "uwb-internal.h"
+
+
+/** Device Address Management command */
+struct uwb_rc_cmd_dev_addr_mgmt {
+ struct uwb_rccb rccb;
+ u8 bmOperationType;
+ u8 baAddr[6];
+} __attribute__((packed));
+
+
+/**
+ * Low level command for setting/getting UWB radio's addresses
+ *
+ * @hwarc: HWA Radio Control interface instance
+ * @bmOperationType:
+ * Set/get, MAC/DEV (see WUSB1.0[8.6.2.2])
+ * @baAddr: address buffer--assumed to have enough data to hold
+ * the address type requested.
+ * @reply: Pointer to reply buffer (can be stack allocated)
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * @cmd has to be allocated because USB cannot grok USB or vmalloc
+ * buffers depending on your combination of host architecture.
+ */
+static
+int uwb_rc_dev_addr_mgmt(struct uwb_rc *rc,
+ u8 bmOperationType, const u8 *baAddr,
+ struct uwb_rc_evt_dev_addr_mgmt *reply)
+{
+ int result;
+ struct uwb_rc_cmd_dev_addr_mgmt *cmd;
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_kzalloc;
+ cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_DEV_ADDR_MGMT);
+ cmd->bmOperationType = bmOperationType;
+ if (baAddr) {
+ size_t size = 0;
+ switch (bmOperationType >> 1) {
+ case 0: size = 2; break;
+ case 1: size = 6; break;
+ default: BUG();
+ }
+ memcpy(cmd->baAddr, baAddr, size);
+ }
+ reply->rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply->rceb.wEvent = UWB_RC_CMD_DEV_ADDR_MGMT;
+ result = uwb_rc_cmd(rc, "DEV-ADDR-MGMT",
+ &cmd->rccb, sizeof(*cmd),
+ &reply->rceb, sizeof(*reply));
+ if (result < 0)
+ goto error_cmd;
+ if (result < sizeof(*reply)) {
+ dev_err(&rc->uwb_dev.dev,
+ "DEV-ADDR-MGMT: not enough data replied: "
+ "%d vs %zu bytes needed\n", result, sizeof(*reply));
+ result = -ENOMSG;
+ } else if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "DEV-ADDR-MGMT: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply->bResultCode),
+ reply->bResultCode);
+ result = -EIO;
+ } else
+ result = 0;
+error_cmd:
+ kfree(cmd);
+error_kzalloc:
+ return result;
+}
+
+
+/**
+ * Set the UWB RC MAC or device address.
+ *
+ * @rc: UWB Radio Controller
+ * @_addr: Pointer to address to write [assumed to be either a
+ * 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *'].
+ * @type: Type of address to set (UWB_ADDR_DEV or UWB_ADDR_MAC).
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * Some anal retentivity here: even if both 'struct
+ * uwb_{dev,mac}_addr' have the actual byte array in the same offset
+ * and I could just pass _addr to hwarc_cmd_dev_addr_mgmt(), I prefer
+ * to use some syntatic sugar in case someday we decide to change the
+ * format of the structs. The compiler will optimize it out anyway.
+ */
+static int uwb_rc_addr_set(struct uwb_rc *rc,
+ const void *_addr, enum uwb_addr_type type)
+{
+ int result;
+ u8 bmOperationType = 0x1; /* Set address */
+ const struct uwb_dev_addr *dev_addr = _addr;
+ const struct uwb_mac_addr *mac_addr = _addr;
+ struct uwb_rc_evt_dev_addr_mgmt reply;
+ const u8 *baAddr;
+
+ result = -EINVAL;
+ switch (type) {
+ case UWB_ADDR_DEV:
+ baAddr = dev_addr->data;
+ break;
+ case UWB_ADDR_MAC:
+ baAddr = mac_addr->data;
+ bmOperationType |= 0x2;
+ break;
+ default:
+ return result;
+ }
+ return uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &reply);
+}
+
+
+/**
+ * Get the UWB radio's MAC or device address.
+ *
+ * @rc: UWB Radio Controller
+ * @_addr: Where to write the address data [assumed to be either a
+ * 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *'].
+ * @type: Type of address to get (UWB_ADDR_DEV or UWB_ADDR_MAC).
+ * @returns: 0 if ok (and *_addr set), < 0 errno code on error.
+ *
+ * See comment in uwb_rc_addr_set() about anal retentivity in the
+ * type handling of the address variables.
+ */
+static int uwb_rc_addr_get(struct uwb_rc *rc,
+ void *_addr, enum uwb_addr_type type)
+{
+ int result;
+ u8 bmOperationType = 0x0; /* Get address */
+ struct uwb_rc_evt_dev_addr_mgmt evt;
+ struct uwb_dev_addr *dev_addr = _addr;
+ struct uwb_mac_addr *mac_addr = _addr;
+ u8 *baAddr;
+
+ result = -EINVAL;
+ switch (type) {
+ case UWB_ADDR_DEV:
+ baAddr = dev_addr->data;
+ break;
+ case UWB_ADDR_MAC:
+ bmOperationType |= 0x2;
+ baAddr = mac_addr->data;
+ break;
+ default:
+ return result;
+ }
+ result = uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &evt);
+ if (result == 0)
+ switch (type) {
+ case UWB_ADDR_DEV:
+ memcpy(&dev_addr->data, evt.baAddr,
+ sizeof(dev_addr->data));
+ break;
+ case UWB_ADDR_MAC:
+ memcpy(&mac_addr->data, evt.baAddr,
+ sizeof(mac_addr->data));
+ break;
+ default: /* shut gcc up */
+ BUG();
+ }
+ return result;
+}
+
+
+/** Get @rc's MAC address to @addr */
+int uwb_rc_mac_addr_get(struct uwb_rc *rc,
+ struct uwb_mac_addr *addr) {
+ return uwb_rc_addr_get(rc, addr, UWB_ADDR_MAC);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_mac_addr_get);
+
+
+/** Get @rc's device address to @addr */
+int uwb_rc_dev_addr_get(struct uwb_rc *rc,
+ struct uwb_dev_addr *addr) {
+ return uwb_rc_addr_get(rc, addr, UWB_ADDR_DEV);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_dev_addr_get);
+
+
+/** Set @rc's address to @addr */
+int uwb_rc_mac_addr_set(struct uwb_rc *rc,
+ const struct uwb_mac_addr *addr)
+{
+ int result = -EINVAL;
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = uwb_rc_addr_set(rc, addr, UWB_ADDR_MAC);
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+
+/** Set @rc's address to @addr */
+int uwb_rc_dev_addr_set(struct uwb_rc *rc,
+ const struct uwb_dev_addr *addr)
+{
+ int result = -EINVAL;
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = uwb_rc_addr_set(rc, addr, UWB_ADDR_DEV);
+ rc->uwb_dev.dev_addr = *addr;
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+/* Returns !0 if given address is already assigned to device. */
+int __uwb_mac_addr_assigned_check(struct device *dev, void *_addr)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_mac_addr *addr = _addr;
+
+ if (!uwb_mac_addr_cmp(addr, &uwb_dev->mac_addr))
+ return !0;
+ return 0;
+}
+
+/* Returns !0 if given address is already assigned to device. */
+int __uwb_dev_addr_assigned_check(struct device *dev, void *_addr)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_dev_addr *addr = _addr;
+ if (!uwb_dev_addr_cmp(addr, &uwb_dev->dev_addr))
+ return !0;
+ return 0;
+}
+
+/**
+ * uwb_dev_addr_assign - assigned a generated DevAddr to a radio controller
+ * @rc: the (local) radio controller device requiring a new DevAddr
+ *
+ * A new DevAddr is required when:
+ * - first setting up a radio controller
+ * - if the hardware reports a DevAddr conflict
+ *
+ * The DevAddr is randomly generated in the generated DevAddr range
+ * [0x100, 0xfeff]. The number of devices in a beacon group is limited
+ * by mMaxBPLength (96) so this address space will never be exhausted.
+ *
+ * [ECMA-368] 17.1.1, 17.16.
+ */
+int uwb_rc_dev_addr_assign(struct uwb_rc *rc)
+{
+ struct uwb_dev_addr new_addr;
+
+ do {
+ get_random_bytes(new_addr.data, sizeof(new_addr.data));
+ } while (new_addr.data[0] == 0x00 || new_addr.data[0] == 0xff
+ || __uwb_dev_addr_assigned(rc, &new_addr));
+
+ return uwb_rc_dev_addr_set(rc, &new_addr);
+}
+
+/**
+ * uwbd_evt_handle_rc_dev_addr_conflict - handle a DEV_ADDR_CONFLICT event
+ * @evt: the DEV_ADDR_CONFLICT notification from the radio controller
+ *
+ * A new (non-conflicting) DevAddr is assigned to the radio controller.
+ *
+ * [ECMA-368] 17.1.1.1.
+ */
+int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt)
+{
+ struct uwb_rc *rc = evt->rc;
+
+ return uwb_rc_dev_addr_assign(rc);
+}
+
+/*
+ * Print the 48-bit EUI MAC address of the radio controller when
+ * reading /sys/class/uwb_rc/XX/mac_address
+ */
+static ssize_t uwb_rc_mac_addr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ struct uwb_mac_addr addr;
+ ssize_t result;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = uwb_rc_addr_get(rc, &addr, UWB_ADDR_MAC);
+ mutex_unlock(&rc->uwb_dev.mutex);
+ if (result >= 0) {
+ result = uwb_mac_addr_print(buf, UWB_ADDR_STRSIZE, &addr);
+ buf[result++] = '\n';
+ }
+ return result;
+}
+
+/*
+ * Parse a 48 bit address written to /sys/class/uwb_rc/XX/mac_address
+ * and if correct, set it.
+ */
+static ssize_t uwb_rc_mac_addr_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ struct uwb_mac_addr addr;
+ ssize_t result;
+
+ result = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\n",
+ &addr.data[0], &addr.data[1], &addr.data[2],
+ &addr.data[3], &addr.data[4], &addr.data[5]);
+ if (result != 6) {
+ result = -EINVAL;
+ goto out;
+ }
+ if (is_multicast_ether_addr(addr.data)) {
+ dev_err(&rc->uwb_dev.dev, "refusing to set multicast "
+ "MAC address %s\n", buf);
+ result = -EINVAL;
+ goto out;
+ }
+ result = uwb_rc_mac_addr_set(rc, &addr);
+ if (result == 0)
+ rc->uwb_dev.mac_addr = addr;
+out:
+ return result < 0 ? result : size;
+}
+DEVICE_ATTR(mac_address, S_IRUGO | S_IWUSR, uwb_rc_mac_addr_show, uwb_rc_mac_addr_store);
+
+/** Print @addr to @buf, @return bytes written */
+size_t __uwb_addr_print(char *buf, size_t buf_size, const unsigned char *addr,
+ int type)
+{
+ size_t result;
+ if (type)
+ result = scnprintf(buf, buf_size,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ addr[0], addr[1], addr[2],
+ addr[3], addr[4], addr[5]);
+ else
+ result = scnprintf(buf, buf_size, "%02x:%02x",
+ addr[1], addr[0]);
+ return result;
+}
+EXPORT_SYMBOL_GPL(__uwb_addr_print);
diff --git a/drivers/uwb/beacon.c b/drivers/uwb/beacon.c
new file mode 100644
index 00000000000..46b18eec502
--- /dev/null
+++ b/drivers/uwb/beacon.c
@@ -0,0 +1,642 @@
+/*
+ * Ultra Wide Band
+ * Beacon management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include "uwb-internal.h"
+
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+/** Start Beaconing command structure */
+struct uwb_rc_cmd_start_beacon {
+ struct uwb_rccb rccb;
+ __le16 wBPSTOffset;
+ u8 bChannelNumber;
+} __attribute__((packed));
+
+
+static int uwb_rc_start_beacon(struct uwb_rc *rc, u16 bpst_offset, u8 channel)
+{
+ int result;
+ struct uwb_rc_cmd_start_beacon *cmd;
+ struct uwb_rc_evt_confirm reply;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+ cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_START_BEACON);
+ cmd->wBPSTOffset = cpu_to_le16(bpst_offset);
+ cmd->bChannelNumber = channel;
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_START_BEACON;
+ result = uwb_rc_cmd(rc, "START-BEACON", &cmd->rccb, sizeof(*cmd),
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "START-BEACON: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ }
+error_cmd:
+ kfree(cmd);
+ return result;
+}
+
+static int uwb_rc_stop_beacon(struct uwb_rc *rc)
+{
+ int result;
+ struct uwb_rccb *cmd;
+ struct uwb_rc_evt_confirm reply;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+ cmd->bCommandType = UWB_RC_CET_GENERAL;
+ cmd->wCommand = cpu_to_le16(UWB_RC_CMD_STOP_BEACON);
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_STOP_BEACON;
+ result = uwb_rc_cmd(rc, "STOP-BEACON", cmd, sizeof(*cmd),
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "STOP-BEACON: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ }
+error_cmd:
+ kfree(cmd);
+ return result;
+}
+
+/*
+ * Start/stop beacons
+ *
+ * @rc: UWB Radio Controller to operate on
+ * @channel: UWB channel on which to beacon (WUSB[table
+ * 5-12]). If -1, stop beaconing.
+ * @bpst_offset: Beacon Period Start Time offset; FIXME-do zero
+ *
+ * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
+ * of a SET IE command after the device sent the first beacon that includes
+ * the IEs specified in the SET IE command. So, after we start beaconing we
+ * check if there is anything in the IE cache and call the SET IE command
+ * if needed.
+ */
+int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ if (channel < 0)
+ channel = -1;
+ if (channel == -1)
+ result = uwb_rc_stop_beacon(rc);
+ else {
+ /* channel >= 0...dah */
+ result = uwb_rc_start_beacon(rc, bpst_offset, channel);
+ if (result < 0)
+ goto out_up;
+ if (le16_to_cpu(rc->ies->wIELength) > 0) {
+ result = uwb_rc_set_ie(rc, rc->ies);
+ if (result < 0) {
+ dev_err(dev, "Cannot set new IE on device: "
+ "%d\n", result);
+ result = uwb_rc_stop_beacon(rc);
+ channel = -1;
+ bpst_offset = 0;
+ } else
+ result = 0;
+ }
+ }
+
+ if (result < 0)
+ goto out_up;
+ rc->beaconing = channel;
+
+ uwb_notify(rc, NULL, uwb_bg_joined(rc) ? UWB_NOTIF_BG_JOIN : UWB_NOTIF_BG_LEAVE);
+
+out_up:
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+/*
+ * Beacon cache
+ *
+ * The purpose of this is to speed up the lookup of becon information
+ * when a new beacon arrives. The UWB Daemon uses it also to keep a
+ * tab of which devices are in radio distance and which not. When a
+ * device's beacon stays present for more than a certain amount of
+ * time, it is considered a new, usable device. When a beacon ceases
+ * to be received for a certain amount of time, it is considered that
+ * the device is gone.
+ *
+ * FIXME: use an allocator for the entries
+ * FIXME: use something faster for search than a list
+ */
+
+struct uwb_beca uwb_beca = {
+ .list = LIST_HEAD_INIT(uwb_beca.list),
+ .mutex = __MUTEX_INITIALIZER(uwb_beca.mutex)
+};
+
+
+void uwb_bce_kfree(struct kref *_bce)
+{
+ struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt);
+
+ kfree(bce->be);
+ kfree(bce);
+}
+
+
+/* Find a beacon by dev addr in the cache */
+static
+struct uwb_beca_e *__uwb_beca_find_bydev(const struct uwb_dev_addr *dev_addr)
+{
+ struct uwb_beca_e *bce, *next;
+ list_for_each_entry_safe(bce, next, &uwb_beca.list, node) {
+ d_printf(6, NULL, "looking for addr %02x:%02x in %02x:%02x\n",
+ dev_addr->data[0], dev_addr->data[1],
+ bce->dev_addr.data[0], bce->dev_addr.data[1]);
+ if (!memcmp(&bce->dev_addr, dev_addr, sizeof(bce->dev_addr)))
+ goto out;
+ }
+ bce = NULL;
+out:
+ return bce;
+}
+
+/* Find a beacon by dev addr in the cache */
+static
+struct uwb_beca_e *__uwb_beca_find_bymac(const struct uwb_mac_addr *mac_addr)
+{
+ struct uwb_beca_e *bce, *next;
+ list_for_each_entry_safe(bce, next, &uwb_beca.list, node) {
+ if (!memcmp(bce->mac_addr, mac_addr->data,
+ sizeof(struct uwb_mac_addr)))
+ goto out;
+ }
+ bce = NULL;
+out:
+ return bce;
+}
+
+/**
+ * uwb_dev_get_by_devaddr - get a UWB device with a specific DevAddr
+ * @rc: the radio controller that saw the device
+ * @devaddr: DevAddr of the UWB device to find
+ *
+ * There may be more than one matching device (in the case of a
+ * DevAddr conflict), but only the first one is returned.
+ */
+struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
+ const struct uwb_dev_addr *devaddr)
+{
+ struct uwb_dev *found = NULL;
+ struct uwb_beca_e *bce;
+
+ mutex_lock(&uwb_beca.mutex);
+ bce = __uwb_beca_find_bydev(devaddr);
+ if (bce)
+ found = uwb_dev_try_get(rc, bce->uwb_dev);
+ mutex_unlock(&uwb_beca.mutex);
+
+ return found;
+}
+
+/**
+ * uwb_dev_get_by_macaddr - get a UWB device with a specific EUI-48
+ * @rc: the radio controller that saw the device
+ * @devaddr: EUI-48 of the UWB device to find
+ */
+struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
+ const struct uwb_mac_addr *macaddr)
+{
+ struct uwb_dev *found = NULL;
+ struct uwb_beca_e *bce;
+
+ mutex_lock(&uwb_beca.mutex);
+ bce = __uwb_beca_find_bymac(macaddr);
+ if (bce)
+ found = uwb_dev_try_get(rc, bce->uwb_dev);
+ mutex_unlock(&uwb_beca.mutex);
+
+ return found;
+}
+
+/* Initialize a beacon cache entry */
+static void uwb_beca_e_init(struct uwb_beca_e *bce)
+{
+ mutex_init(&bce->mutex);
+ kref_init(&bce->refcnt);
+ stats_init(&bce->lqe_stats);
+ stats_init(&bce->rssi_stats);
+}
+
+/*
+ * Add a beacon to the cache
+ *
+ * @be: Beacon event information
+ * @bf: Beacon frame (part of b, really)
+ * @ts_jiffies: Timestamp (in jiffies) when the beacon was received
+ */
+struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *be,
+ struct uwb_beacon_frame *bf,
+ unsigned long ts_jiffies)
+{
+ struct uwb_beca_e *bce;
+
+ bce = kzalloc(sizeof(*bce), GFP_KERNEL);
+ if (bce == NULL)
+ return NULL;
+ uwb_beca_e_init(bce);
+ bce->ts_jiffies = ts_jiffies;
+ bce->uwb_dev = NULL;
+ list_add(&bce->node, &uwb_beca.list);
+ return bce;
+}
+
+/*
+ * Wipe out beacon entries that became stale
+ *
+ * Remove associated devicest too.
+ */
+void uwb_beca_purge(void)
+{
+ struct uwb_beca_e *bce, *next;
+ unsigned long expires;
+
+ mutex_lock(&uwb_beca.mutex);
+ list_for_each_entry_safe(bce, next, &uwb_beca.list, node) {
+ expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms);
+ if (time_after(jiffies, expires)) {
+ uwbd_dev_offair(bce);
+ list_del(&bce->node);
+ uwb_bce_put(bce);
+ }
+ }
+ mutex_unlock(&uwb_beca.mutex);
+}
+
+/* Clean up the whole beacon cache. Called on shutdown */
+void uwb_beca_release(void)
+{
+ struct uwb_beca_e *bce, *next;
+ mutex_lock(&uwb_beca.mutex);
+ list_for_each_entry_safe(bce, next, &uwb_beca.list, node) {
+ list_del(&bce->node);
+ uwb_bce_put(bce);
+ }
+ mutex_unlock(&uwb_beca.mutex);
+}
+
+static void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be,
+ struct uwb_beacon_frame *bf)
+{
+ char macbuf[UWB_ADDR_STRSIZE];
+ char devbuf[UWB_ADDR_STRSIZE];
+ char dstbuf[UWB_ADDR_STRSIZE];
+
+ uwb_mac_addr_print(macbuf, sizeof(macbuf), &bf->Device_Identifier);
+ uwb_dev_addr_print(devbuf, sizeof(devbuf), &bf->hdr.SrcAddr);
+ uwb_dev_addr_print(dstbuf, sizeof(dstbuf), &bf->hdr.DestAddr);
+ dev_info(&rc->uwb_dev.dev,
+ "BEACON from %s to %s (ch%u offset %u slot %u MAC %s)\n",
+ devbuf, dstbuf, be->bChannelNumber, be->wBPSTOffset,
+ bf->Beacon_Slot_Number, macbuf);
+}
+
+/*
+ * @bce: beacon cache entry, referenced
+ */
+ssize_t uwb_bce_print_IEs(struct uwb_dev *uwb_dev, struct uwb_beca_e *bce,
+ char *buf, size_t size)
+{
+ ssize_t result = 0;
+ struct uwb_rc_evt_beacon *be;
+ struct uwb_beacon_frame *bf;
+ struct uwb_buf_ctx ctx = {
+ .buf = buf,
+ .bytes = 0,
+ .size = size
+ };
+
+ mutex_lock(&bce->mutex);
+ be = bce->be;
+ if (be == NULL)
+ goto out;
+ bf = (void *) be->BeaconInfo;
+ uwb_ie_for_each(uwb_dev, uwb_ie_dump_hex, &ctx,
+ bf->IEData, be->wBeaconInfoLength - sizeof(*bf));
+ result = ctx.bytes;
+out:
+ mutex_unlock(&bce->mutex);
+ return result;
+}
+
+/*
+ * Verify that the beacon event, frame and IEs are ok
+ */
+static int uwb_verify_beacon(struct uwb_rc *rc, struct uwb_event *evt,
+ struct uwb_rc_evt_beacon *be)
+{
+ int result = -EINVAL;
+ struct uwb_beacon_frame *bf;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ /* Is there enough data to decode a beacon frame? */
+ if (evt->notif.size < sizeof(*be) + sizeof(*bf)) {
+ dev_err(dev, "BEACON event: Not enough data to decode "
+ "(%zu vs %zu bytes needed)\n", evt->notif.size,
+ sizeof(*be) + sizeof(*bf));
+ goto error;
+ }
+ /* FIXME: make sure beacon frame IEs are fine and that the whole thing
+ * is consistent */
+ result = 0;
+error:
+ return result;
+}
+
+/*
+ * Handle UWB_RC_EVT_BEACON events
+ *
+ * We check the beacon cache to see how the received beacon fares. If
+ * is there already we refresh the timestamp. If not we create a new
+ * entry.
+ *
+ * According to the WHCI and WUSB specs, only one beacon frame is
+ * allowed per notification block, so we don't bother about scanning
+ * for more.
+ */
+int uwbd_evt_handle_rc_beacon(struct uwb_event *evt)
+{
+ int result = -EINVAL;
+ struct uwb_rc *rc;
+ struct uwb_rc_evt_beacon *be;
+ struct uwb_beacon_frame *bf;
+ struct uwb_beca_e *bce;
+ unsigned long last_ts;
+
+ rc = evt->rc;
+ be = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon, rceb);
+ result = uwb_verify_beacon(rc, evt, be);
+ if (result < 0)
+ return result;
+
+ /* FIXME: handle alien beacons. */
+ if (be->bBeaconType == UWB_RC_BEACON_TYPE_OL_ALIEN ||
+ be->bBeaconType == UWB_RC_BEACON_TYPE_NOL_ALIEN) {
+ return -ENOSYS;
+ }
+
+ bf = (struct uwb_beacon_frame *) be->BeaconInfo;
+
+ /*
+ * Drop beacons from devices with a NULL EUI-48 -- they cannot
+ * be uniquely identified.
+ *
+ * It's expected that these will all be WUSB devices and they
+ * have a WUSB specific connection method so ignoring them
+ * here shouldn't be a problem.
+ */
+ if (uwb_mac_addr_bcast(&bf->Device_Identifier))
+ return 0;
+
+ mutex_lock(&uwb_beca.mutex);
+ bce = __uwb_beca_find_bymac(&bf->Device_Identifier);
+ if (bce == NULL) {
+ /* Not in there, a new device is pinging */
+ uwb_beacon_print(evt->rc, be, bf);
+ bce = __uwb_beca_add(be, bf, evt->ts_jiffies);
+ if (bce == NULL) {
+ mutex_unlock(&uwb_beca.mutex);
+ return -ENOMEM;
+ }
+ }
+ mutex_unlock(&uwb_beca.mutex);
+
+ mutex_lock(&bce->mutex);
+ /* purge old beacon data */
+ kfree(bce->be);
+
+ last_ts = bce->ts_jiffies;
+
+ /* Update commonly used fields */
+ bce->ts_jiffies = evt->ts_jiffies;
+ bce->be = be;
+ bce->dev_addr = bf->hdr.SrcAddr;
+ bce->mac_addr = &bf->Device_Identifier;
+ be->wBPSTOffset = le16_to_cpu(be->wBPSTOffset);
+ be->wBeaconInfoLength = le16_to_cpu(be->wBeaconInfoLength);
+ stats_add_sample(&bce->lqe_stats, be->bLQI - 7);
+ stats_add_sample(&bce->rssi_stats, be->bRSSI + 18);
+
+ /*
+ * This might be a beacon from a new device.
+ */
+ if (bce->uwb_dev == NULL)
+ uwbd_dev_onair(evt->rc, bce);
+
+ mutex_unlock(&bce->mutex);
+
+ return 1; /* we keep the event data */
+}
+
+/*
+ * Handle UWB_RC_EVT_BEACON_SIZE events
+ *
+ * XXXXX
+ */
+int uwbd_evt_handle_rc_beacon_size(struct uwb_event *evt)
+{
+ int result = -EINVAL;
+ struct device *dev = &evt->rc->uwb_dev.dev;
+ struct uwb_rc_evt_beacon_size *bs;
+
+ /* Is there enough data to decode the event? */
+ if (evt->notif.size < sizeof(*bs)) {
+ dev_err(dev, "BEACON SIZE notification: Not enough data to "
+ "decode (%zu vs %zu bytes needed)\n",
+ evt->notif.size, sizeof(*bs));
+ goto error;
+ }
+ bs = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon_size, rceb);
+ if (0)
+ dev_info(dev, "Beacon size changed to %u bytes "
+ "(FIXME: action?)\n", le16_to_cpu(bs->wNewBeaconSize));
+ else {
+ /* temporary hack until we do something with this message... */
+ static unsigned count;
+ if (++count % 1000 == 0)
+ dev_info(dev, "Beacon size changed %u times "
+ "(FIXME: action?)\n", count);
+ }
+ result = 0;
+error:
+ return result;
+}
+
+/**
+ * uwbd_evt_handle_rc_bp_slot_change - handle a BP_SLOT_CHANGE event
+ * @evt: the BP_SLOT_CHANGE notification from the radio controller
+ *
+ * If the event indicates that no beacon period slots were available
+ * then radio controller has transitioned to a non-beaconing state.
+ * Otherwise, simply save the current beacon slot.
+ */
+int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *evt)
+{
+ struct uwb_rc *rc = evt->rc;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_evt_bp_slot_change *bpsc;
+
+ if (evt->notif.size < sizeof(*bpsc)) {
+ dev_err(dev, "BP SLOT CHANGE event: Not enough data\n");
+ return -EINVAL;
+ }
+ bpsc = container_of(evt->notif.rceb, struct uwb_rc_evt_bp_slot_change, rceb);
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ if (uwb_rc_evt_bp_slot_change_no_slot(bpsc)) {
+ dev_info(dev, "stopped beaconing: No free slots in BP\n");
+ rc->beaconing = -1;
+ } else
+ rc->uwb_dev.beacon_slot = uwb_rc_evt_bp_slot_change_slot_num(bpsc);
+ mutex_unlock(&rc->uwb_dev.mutex);
+
+ return 0;
+}
+
+/**
+ * Handle UWB_RC_EVT_BPOIE_CHANGE events
+ *
+ * XXXXX
+ */
+struct uwb_ie_bpo {
+ struct uwb_ie_hdr hdr;
+ u8 bp_length;
+ u8 data[];
+} __attribute__((packed));
+
+int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *evt)
+{
+ int result = -EINVAL;
+ struct device *dev = &evt->rc->uwb_dev.dev;
+ struct uwb_rc_evt_bpoie_change *bpoiec;
+ struct uwb_ie_bpo *bpoie;
+ static unsigned count; /* FIXME: this is a temp hack */
+ size_t iesize;
+
+ /* Is there enough data to decode it? */
+ if (evt->notif.size < sizeof(*bpoiec)) {
+ dev_err(dev, "BPOIEC notification: Not enough data to "
+ "decode (%zu vs %zu bytes needed)\n",
+ evt->notif.size, sizeof(*bpoiec));
+ goto error;
+ }
+ bpoiec = container_of(evt->notif.rceb, struct uwb_rc_evt_bpoie_change, rceb);
+ iesize = le16_to_cpu(bpoiec->wBPOIELength);
+ if (iesize < sizeof(*bpoie)) {
+ dev_err(dev, "BPOIEC notification: Not enough IE data to "
+ "decode (%zu vs %zu bytes needed)\n",
+ iesize, sizeof(*bpoie));
+ goto error;
+ }
+ if (++count % 1000 == 0) /* Lame placeholder */
+ dev_info(dev, "BPOIE: %u changes received\n", count);
+ /*
+ * FIXME: At this point we should go over all the IEs in the
+ * bpoiec->BPOIE array and act on each.
+ */
+ result = 0;
+error:
+ return result;
+}
+
+/**
+ * uwb_bg_joined - is the RC in a beacon group?
+ * @rc: the radio controller
+ *
+ * Returns true if the radio controller is in a beacon group (even if
+ * it's the sole member).
+ */
+int uwb_bg_joined(struct uwb_rc *rc)
+{
+ return rc->beaconing != -1;
+}
+EXPORT_SYMBOL_GPL(uwb_bg_joined);
+
+/*
+ * Print beaconing state.
+ */
+static ssize_t uwb_rc_beacon_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ ssize_t result;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = sprintf(buf, "%d\n", rc->beaconing);
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+/*
+ * Start beaconing on the specified channel, or stop beaconing.
+ *
+ * The BPST offset of when to start searching for a beacon group to
+ * join may be specified.
+ */
+static ssize_t uwb_rc_beacon_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ int channel;
+ unsigned bpst_offset = 0;
+ ssize_t result = -EINVAL;
+
+ result = sscanf(buf, "%d %u\n", &channel, &bpst_offset);
+ if (result >= 1)
+ result = uwb_rc_beacon(rc, channel, bpst_offset);
+
+ return result < 0 ? result : size;
+}
+DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, uwb_rc_beacon_show, uwb_rc_beacon_store);
diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c
new file mode 100644
index 00000000000..521cdeb8497
--- /dev/null
+++ b/drivers/uwb/driver.c
@@ -0,0 +1,144 @@
+/*
+ * Ultra Wide Band
+ * Driver initialization, etc
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ *
+ * Life cycle: FIXME: explain
+ *
+ * UWB radio controller:
+ *
+ * 1. alloc a uwb_rc, zero it
+ * 2. call uwb_rc_init() on it to set it up + ops (won't do any
+ * kind of allocation)
+ * 3. register (now it is owned by the UWB stack--deregister before
+ * freeing/destroying).
+ * 4. It lives on it's own now (UWB stack handles)--when it
+ * disconnects, call unregister()
+ * 5. free it.
+ *
+ * Make sure you have a reference to the uwb_rc before calling
+ * any of the UWB API functions.
+ *
+ * TODO:
+ *
+ * 1. Locking and life cycle management is crappy still. All entry
+ * points to the UWB HCD API assume you have a reference on the
+ * uwb_rc structure and that it won't go away. They mutex lock it
+ * before doing anything.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/random.h>
+#include <linux/uwb/debug.h>
+#include "uwb-internal.h"
+
+
+/* UWB stack attributes (or 'global' constants) */
+
+
+/**
+ * If a beacon dissapears for longer than this, then we consider the
+ * device who was represented by that beacon to be gone.
+ *
+ * ECMA-368[17.2.3, last para] establishes that a device must not
+ * consider a device to be its neighbour if he doesn't receive a beacon
+ * for more than mMaxLostBeacons. mMaxLostBeacons is defined in
+ * ECMA-368[17.16] as 3; because we can get only one beacon per
+ * superframe, that'd be 3 * 65ms = 195 ~ 200 ms. Let's give it time
+ * for jitter and stuff and make it 500 ms.
+ */
+unsigned long beacon_timeout_ms = 500;
+
+static
+ssize_t beacon_timeout_ms_show(struct class *class, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms);
+}
+
+static
+ssize_t beacon_timeout_ms_store(struct class *class,
+ const char *buf, size_t size)
+{
+ unsigned long bt;
+ ssize_t result;
+ result = sscanf(buf, "%lu", &bt);
+ if (result != 1)
+ return -EINVAL;
+ beacon_timeout_ms = bt;
+ return size;
+}
+
+static struct class_attribute uwb_class_attrs[] = {
+ __ATTR(beacon_timeout_ms, S_IWUSR | S_IRUGO,
+ beacon_timeout_ms_show, beacon_timeout_ms_store),
+ __ATTR_NULL,
+};
+
+/** Device model classes */
+struct class uwb_rc_class = {
+ .name = "uwb_rc",
+ .class_attrs = uwb_class_attrs,
+};
+
+
+static int __init uwb_subsys_init(void)
+{
+ int result = 0;
+
+ result = uwb_est_create();
+ if (result < 0) {
+ printk(KERN_ERR "uwb: Can't initialize EST subsystem\n");
+ goto error_est_init;
+ }
+
+ result = class_register(&uwb_rc_class);
+ if (result < 0)
+ goto error_uwb_rc_class_register;
+ uwbd_start();
+ uwb_dbg_init();
+ return 0;
+
+error_uwb_rc_class_register:
+ uwb_est_destroy();
+error_est_init:
+ return result;
+}
+module_init(uwb_subsys_init);
+
+static void __exit uwb_subsys_exit(void)
+{
+ uwb_dbg_exit();
+ uwbd_stop();
+ class_unregister(&uwb_rc_class);
+ uwb_est_destroy();
+ return;
+}
+module_exit(uwb_subsys_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Ultra Wide Band core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/drp-avail.c b/drivers/uwb/drp-avail.c
new file mode 100644
index 00000000000..3febd855280
--- /dev/null
+++ b/drivers/uwb/drp-avail.c
@@ -0,0 +1,288 @@
+/*
+ * Ultra Wide Band
+ * DRP availability management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Reinette Chatre <reinette.chatre@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Manage DRP Availability (the MAS available for DRP
+ * reservations). Thus:
+ *
+ * - Handle DRP Availability Change notifications
+ *
+ * - Allow the reservation manager to indicate MAS reserved/released
+ * by local (owned by/targeted at the radio controller)
+ * reservations.
+ *
+ * - Based on the two sources above, generate a DRP Availability IE to
+ * be included in the beacon.
+ *
+ * See also the documentation for struct uwb_drp_avail.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/bitmap.h>
+#include "uwb-internal.h"
+
+/**
+ * uwb_drp_avail_init - initialize an RC's MAS availability
+ *
+ * All MAS are available initially. The RC will inform use which
+ * slots are used for the BP (it may change in size).
+ */
+void uwb_drp_avail_init(struct uwb_rc *rc)
+{
+ bitmap_fill(rc->drp_avail.global, UWB_NUM_MAS);
+ bitmap_fill(rc->drp_avail.local, UWB_NUM_MAS);
+ bitmap_fill(rc->drp_avail.pending, UWB_NUM_MAS);
+}
+
+/*
+ * Determine MAS available for new local reservations.
+ *
+ * avail = global & local & pending
+ */
+static void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail)
+{
+ bitmap_and(avail->bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS);
+ bitmap_and(avail->bm, avail->bm, rc->drp_avail.pending, UWB_NUM_MAS);
+}
+
+/**
+ * uwb_drp_avail_reserve_pending - reserve MAS for a new reservation
+ * @rc: the radio controller
+ * @mas: the MAS to reserve
+ *
+ * Returns 0 on success, or -EBUSY if the MAS requested aren't available.
+ */
+int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas)
+{
+ struct uwb_mas_bm avail;
+
+ uwb_drp_available(rc, &avail);
+ if (!bitmap_subset(mas->bm, avail.bm, UWB_NUM_MAS))
+ return -EBUSY;
+
+ bitmap_andnot(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
+ return 0;
+}
+
+/**
+ * uwb_drp_avail_reserve - reserve MAS for an established reservation
+ * @rc: the radio controller
+ * @mas: the MAS to reserve
+ */
+void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas)
+{
+ bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
+ bitmap_andnot(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS);
+ rc->drp_avail.ie_valid = false;
+}
+
+/**
+ * uwb_drp_avail_release - release MAS from a pending or established reservation
+ * @rc: the radio controller
+ * @mas: the MAS to release
+ */
+void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas)
+{
+ bitmap_or(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS);
+ bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
+ rc->drp_avail.ie_valid = false;
+}
+
+/**
+ * uwb_drp_avail_ie_update - update the DRP Availability IE
+ * @rc: the radio controller
+ *
+ * avail = global & local
+ */
+void uwb_drp_avail_ie_update(struct uwb_rc *rc)
+{
+ struct uwb_mas_bm avail;
+
+ bitmap_and(avail.bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS);
+
+ rc->drp_avail.ie.hdr.element_id = UWB_IE_DRP_AVAILABILITY;
+ rc->drp_avail.ie.hdr.length = UWB_NUM_MAS / 8;
+ uwb_mas_bm_copy_le(rc->drp_avail.ie.bmp, &avail);
+ rc->drp_avail.ie_valid = true;
+}
+
+/**
+ * Create an unsigned long from a buffer containing a byte stream.
+ *
+ * @array: pointer to buffer
+ * @itr: index of buffer from where we start
+ * @len: the buffer's remaining size may not be exact multiple of
+ * sizeof(unsigned long), @len is the length of buffer that needs
+ * to be converted. This will be sizeof(unsigned long) or smaller
+ * (BUG if not). If it is smaller then we will pad the remaining
+ * space of the result with zeroes.
+ */
+static
+unsigned long get_val(u8 *array, size_t itr, size_t len)
+{
+ unsigned long val = 0;
+ size_t top = itr + len;
+
+ BUG_ON(len > sizeof(val));
+
+ while (itr < top) {
+ val <<= 8;
+ val |= array[top - 1];
+ top--;
+ }
+ val <<= 8 * (sizeof(val) - len); /* padding */
+ return val;
+}
+
+/**
+ * Initialize bitmap from data buffer.
+ *
+ * The bitmap to be converted could come from a IE, for example a
+ * DRP Availability IE.
+ * From ECMA-368 1.0 [16.8.7]: "
+ * octets: 1 1 N * (0 to 32)
+ * Element ID Length (=N) DRP Availability Bitmap
+ *
+ * The DRP Availability Bitmap field is up to 256 bits long, one
+ * bit for each MAS in the superframe, where the least-significant
+ * bit of the field corresponds to the first MAS in the superframe
+ * and successive bits correspond to successive MASs."
+ *
+ * The DRP Availability bitmap is in octets from 0 to 32, so octet
+ * 32 contains bits for MAS 1-8, etc. If the bitmap is smaller than 32
+ * octets, the bits in octets not included at the end of the bitmap are
+ * treated as zero. In this case (when the bitmap is smaller than 32
+ * octets) the MAS represented range from MAS 1 to MAS (size of bitmap)
+ * with the last octet still containing bits for MAS 1-8, etc.
+ *
+ * For example:
+ * F00F0102 03040506 0708090A 0B0C0D0E 0F010203
+ * ^^^^
+ * ||||
+ * ||||
+ * |||\LSB of byte is MAS 9
+ * ||\MSB of byte is MAS 16
+ * |\LSB of first byte is MAS 1
+ * \ MSB of byte is MAS 8
+ *
+ * An example of this encoding can be found in ECMA-368 Annex-D [Table D.11]
+ *
+ * The resulting bitmap will have the following mapping:
+ * bit position 0 == MAS 1
+ * bit position 1 == MAS 2
+ * ...
+ * bit position (UWB_NUM_MAS - 1) == MAS UWB_NUM_MAS
+ *
+ * @bmp_itr: pointer to bitmap (can be declared with DECLARE_BITMAP)
+ * @buffer: pointer to buffer containing bitmap data in big endian
+ * format (MSB first)
+ * @buffer_size:number of bytes with which bitmap should be initialized
+ */
+static
+void buffer_to_bmp(unsigned long *bmp_itr, void *_buffer,
+ size_t buffer_size)
+{
+ u8 *buffer = _buffer;
+ size_t itr, len;
+ unsigned long val;
+
+ itr = 0;
+ while (itr < buffer_size) {
+ len = buffer_size - itr >= sizeof(val) ?
+ sizeof(val) : buffer_size - itr;
+ val = get_val(buffer, itr, len);
+ bmp_itr[itr / sizeof(val)] = val;
+ itr += sizeof(val);
+ }
+}
+
+
+/**
+ * Extract DRP Availability bitmap from the notification.
+ *
+ * The notification that comes in contains a bitmap of (UWB_NUM_MAS / 8) bytes
+ * We convert that to our internal representation.
+ */
+static
+int uwbd_evt_get_drp_avail(struct uwb_event *evt, unsigned long *bmp)
+{
+ struct device *dev = &evt->rc->uwb_dev.dev;
+ struct uwb_rc_evt_drp_avail *drp_evt;
+ int result = -EINVAL;
+
+ /* Is there enough data to decode the event? */
+ if (evt->notif.size < sizeof(*drp_evt)) {
+ dev_err(dev, "DRP Availability Change: Not enough "
+ "data to decode event [%zu bytes, %zu "
+ "needed]\n", evt->notif.size, sizeof(*drp_evt));
+ goto error;
+ }
+ drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp_avail, rceb);
+ buffer_to_bmp(bmp, drp_evt->bmp, UWB_NUM_MAS/8);
+ result = 0;
+error:
+ return result;
+}
+
+
+/**
+ * Process an incoming DRP Availability notification.
+ *
+ * @evt: Event information (packs the actual event data, which
+ * radio controller it came to, etc).
+ *
+ * @returns: 0 on success (so uwbd() frees the event buffer), < 0
+ * on error.
+ *
+ * According to ECMA-368 1.0 [16.8.7], bits set to ONE indicate that
+ * the MAS slot is available, bits set to ZERO indicate that the slot
+ * is busy.
+ *
+ * So we clear available slots, we set used slots :)
+ *
+ * The notification only marks non-availability based on the BP and
+ * received DRP IEs that are not for this radio controller. A copy of
+ * this bitmap is needed to generate the real availability (which
+ * includes local and pending reservations).
+ *
+ * The DRP Availability IE that this radio controller emits will need
+ * to be updated.
+ */
+int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt)
+{
+ int result;
+ struct uwb_rc *rc = evt->rc;
+ DECLARE_BITMAP(bmp, UWB_NUM_MAS);
+
+ result = uwbd_evt_get_drp_avail(evt, bmp);
+ if (result < 0)
+ return result;
+
+ mutex_lock(&rc->rsvs_mutex);
+ bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS);
+ rc->drp_avail.ie_valid = false;
+ mutex_unlock(&rc->rsvs_mutex);
+
+ uwb_rsv_sched_update(rc);
+
+ return 0;
+}
diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c
new file mode 100644
index 00000000000..882724c5f12
--- /dev/null
+++ b/drivers/uwb/drp-ie.c
@@ -0,0 +1,232 @@
+/*
+ * UWB DRP IE management.
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include <linux/uwb.h>
+
+#include "uwb-internal.h"
+
+/*
+ * Allocate a DRP IE.
+ *
+ * To save having to free/allocate a DRP IE when its MAS changes,
+ * enough memory is allocated for the maxiumum number of DRP
+ * allocation fields. This gives an overhead per reservation of up to
+ * (UWB_NUM_ZONES - 1) * 4 = 60 octets.
+ */
+static struct uwb_ie_drp *uwb_drp_ie_alloc(void)
+{
+ struct uwb_ie_drp *drp_ie;
+ unsigned tiebreaker;
+
+ drp_ie = kzalloc(sizeof(struct uwb_ie_drp) +
+ UWB_NUM_ZONES * sizeof(struct uwb_drp_alloc),
+ GFP_KERNEL);
+ if (drp_ie) {
+ drp_ie->hdr.element_id = UWB_IE_DRP;
+
+ get_random_bytes(&tiebreaker, sizeof(unsigned));
+ uwb_ie_drp_set_tiebreaker(drp_ie, tiebreaker & 1);
+ }
+ return drp_ie;
+}
+
+
+/*
+ * Fill a DRP IE's allocation fields from a MAS bitmap.
+ */
+static void uwb_drp_ie_from_bm(struct uwb_ie_drp *drp_ie,
+ struct uwb_mas_bm *mas)
+{
+ int z, i, num_fields = 0, next = 0;
+ struct uwb_drp_alloc *zones;
+ __le16 current_bmp;
+ DECLARE_BITMAP(tmp_bmp, UWB_NUM_MAS);
+ DECLARE_BITMAP(tmp_mas_bm, UWB_MAS_PER_ZONE);
+
+ zones = drp_ie->allocs;
+
+ bitmap_copy(tmp_bmp, mas->bm, UWB_NUM_MAS);
+
+ /* Determine unique MAS bitmaps in zones from bitmap. */
+ for (z = 0; z < UWB_NUM_ZONES; z++) {
+ bitmap_copy(tmp_mas_bm, tmp_bmp, UWB_MAS_PER_ZONE);
+ if (bitmap_weight(tmp_mas_bm, UWB_MAS_PER_ZONE) > 0) {
+ bool found = false;
+ current_bmp = (__le16) *tmp_mas_bm;
+ for (i = 0; i < next; i++) {
+ if (current_bmp == zones[i].mas_bm) {
+ zones[i].zone_bm |= 1 << z;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ num_fields++;
+ zones[next].zone_bm = 1 << z;
+ zones[next].mas_bm = current_bmp;
+ next++;
+ }
+ }
+ bitmap_shift_right(tmp_bmp, tmp_bmp, UWB_MAS_PER_ZONE, UWB_NUM_MAS);
+ }
+
+ /* Store in format ready for transmission (le16). */
+ for (i = 0; i < num_fields; i++) {
+ drp_ie->allocs[i].zone_bm = cpu_to_le16(zones[i].zone_bm);
+ drp_ie->allocs[i].mas_bm = cpu_to_le16(zones[i].mas_bm);
+ }
+
+ drp_ie->hdr.length = sizeof(struct uwb_ie_drp) - sizeof(struct uwb_ie_hdr)
+ + num_fields * sizeof(struct uwb_drp_alloc);
+}
+
+/**
+ * uwb_drp_ie_update - update a reservation's DRP IE
+ * @rsv: the reservation
+ */
+int uwb_drp_ie_update(struct uwb_rsv *rsv)
+{
+ struct device *dev = &rsv->rc->uwb_dev.dev;
+ struct uwb_ie_drp *drp_ie;
+ int reason_code, status;
+
+ switch (rsv->state) {
+ case UWB_RSV_STATE_NONE:
+ kfree(rsv->drp_ie);
+ rsv->drp_ie = NULL;
+ return 0;
+ case UWB_RSV_STATE_O_INITIATED:
+ reason_code = UWB_DRP_REASON_ACCEPTED;
+ status = 0;
+ break;
+ case UWB_RSV_STATE_O_PENDING:
+ reason_code = UWB_DRP_REASON_ACCEPTED;
+ status = 0;
+ break;
+ case UWB_RSV_STATE_O_MODIFIED:
+ reason_code = UWB_DRP_REASON_MODIFIED;
+ status = 1;
+ break;
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ reason_code = UWB_DRP_REASON_ACCEPTED;
+ status = 1;
+ break;
+ case UWB_RSV_STATE_T_ACCEPTED:
+ reason_code = UWB_DRP_REASON_ACCEPTED;
+ status = 1;
+ break;
+ case UWB_RSV_STATE_T_DENIED:
+ reason_code = UWB_DRP_REASON_DENIED;
+ status = 0;
+ break;
+ default:
+ dev_dbg(dev, "rsv with unhandled state (%d)\n", rsv->state);
+ return -EINVAL;
+ }
+
+ if (rsv->drp_ie == NULL) {
+ rsv->drp_ie = uwb_drp_ie_alloc();
+ if (rsv->drp_ie == NULL)
+ return -ENOMEM;
+ }
+ drp_ie = rsv->drp_ie;
+
+ uwb_ie_drp_set_owner(drp_ie, uwb_rsv_is_owner(rsv));
+ uwb_ie_drp_set_status(drp_ie, status);
+ uwb_ie_drp_set_reason_code(drp_ie, reason_code);
+ uwb_ie_drp_set_stream_index(drp_ie, rsv->stream);
+ uwb_ie_drp_set_type(drp_ie, rsv->type);
+
+ if (uwb_rsv_is_owner(rsv)) {
+ switch (rsv->target.type) {
+ case UWB_RSV_TARGET_DEV:
+ drp_ie->dev_addr = rsv->target.dev->dev_addr;
+ break;
+ case UWB_RSV_TARGET_DEVADDR:
+ drp_ie->dev_addr = rsv->target.devaddr;
+ break;
+ }
+ } else
+ drp_ie->dev_addr = rsv->owner->dev_addr;
+
+ uwb_drp_ie_from_bm(drp_ie, &rsv->mas);
+
+ rsv->ie_valid = true;
+ return 0;
+}
+
+/*
+ * Set MAS bits from given MAS bitmap in a single zone of large bitmap.
+ *
+ * We are given a zone id and the MAS bitmap of bits that need to be set in
+ * this zone. Note that this zone may already have bits set and this only
+ * adds settings - we cannot simply assign the MAS bitmap contents to the
+ * zone contents. We iterate over the the bits (MAS) in the zone and set the
+ * bits that are set in the given MAS bitmap.
+ */
+static
+void uwb_drp_ie_single_zone_to_bm(struct uwb_mas_bm *bm, u8 zone, u16 mas_bm)
+{
+ int mas;
+ u16 mas_mask;
+
+ for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++) {
+ mas_mask = 1 << mas;
+ if (mas_bm & mas_mask)
+ set_bit(zone * UWB_NUM_ZONES + mas, bm->bm);
+ }
+}
+
+/**
+ * uwb_drp_ie_zones_to_bm - convert DRP allocation fields to a bitmap
+ * @mas: MAS bitmap that will be populated to correspond to the
+ * allocation fields in the DRP IE
+ * @drp_ie: the DRP IE that contains the allocation fields.
+ *
+ * The input format is an array of MAS allocation fields (16 bit Zone
+ * bitmap, 16 bit MAS bitmap) as described in [ECMA-368] section
+ * 16.8.6. The output is a full 256 bit MAS bitmap.
+ *
+ * We go over all the allocation fields, for each allocation field we
+ * know which zones are impacted. We iterate over all the zones
+ * impacted and call a function that will set the correct MAS bits in
+ * each zone.
+ */
+void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie)
+{
+ int numallocs = (drp_ie->hdr.length - 4) / 4;
+ const struct uwb_drp_alloc *alloc;
+ int cnt;
+ u16 zone_bm, mas_bm;
+ u8 zone;
+ u16 zone_mask;
+
+ for (cnt = 0; cnt < numallocs; cnt++) {
+ alloc = &drp_ie->allocs[cnt];
+ zone_bm = le16_to_cpu(alloc->zone_bm);
+ mas_bm = le16_to_cpu(alloc->mas_bm);
+ for (zone = 0; zone < UWB_NUM_ZONES; zone++) {
+ zone_mask = 1 << zone;
+ if (zone_bm & zone_mask)
+ uwb_drp_ie_single_zone_to_bm(bm, zone, mas_bm);
+ }
+ }
+}
diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c
new file mode 100644
index 00000000000..c0b1e5e2bd0
--- /dev/null
+++ b/drivers/uwb/drp.c
@@ -0,0 +1,461 @@
+/*
+ * Ultra Wide Band
+ * Dynamic Reservation Protocol handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/delay.h>
+#include "uwb-internal.h"
+
+/**
+ * Construct and send the SET DRP IE
+ *
+ * @rc: UWB Host controller
+ * @returns: >= 0 number of bytes still available in the beacon
+ * < 0 errno code on error.
+ *
+ * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the
+ * device to include in its beacon at the same time. We thus have to
+ * traverse all reservations and include the DRP IEs of all PENDING
+ * and NEGOTIATED reservations in a SET DRP command for transmission.
+ *
+ * A DRP Availability IE is appended.
+ *
+ * rc->uwb_dev.mutex is held
+ *
+ * FIXME We currently ignore the returned value indicating the remaining space
+ * in beacon. This could be used to deny reservation requests earlier if
+ * determined that they would cause the beacon space to be exceeded.
+ */
+static
+int uwb_rc_gen_send_drp_ie(struct uwb_rc *rc)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_cmd_set_drp_ie *cmd;
+ struct uwb_rc_evt_set_drp_ie reply;
+ struct uwb_rsv *rsv;
+ int num_bytes = 0;
+ u8 *IEDataptr;
+
+ result = -ENOMEM;
+ /* First traverse all reservations to determine memory needed. */
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ if (rsv->drp_ie != NULL)
+ num_bytes += rsv->drp_ie->hdr.length + 2;
+ }
+ num_bytes += sizeof(rc->drp_avail.ie);
+ cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL);
+ if (cmd == NULL)
+ goto error;
+ cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE);
+ cmd->wIELength = num_bytes;
+ IEDataptr = (u8 *)&cmd->IEData[0];
+
+ /* Next traverse all reservations to place IEs in allocated memory. */
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ if (rsv->drp_ie != NULL) {
+ memcpy(IEDataptr, rsv->drp_ie,
+ rsv->drp_ie->hdr.length + 2);
+ IEDataptr += rsv->drp_ie->hdr.length + 2;
+ }
+ }
+ memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie));
+
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_SET_DRP_IE;
+ result = uwb_rc_cmd(rc, "SET-DRP-IE", &cmd->rccb,
+ sizeof(*cmd) + num_bytes, &reply.rceb,
+ sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ result = le16_to_cpu(reply.wRemainingSpace);
+ if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: command execution "
+ "failed: %s (%d). RemainingSpace in beacon "
+ "= %d\n", uwb_rc_strerror(reply.bResultCode),
+ reply.bResultCode, result);
+ result = -EIO;
+ } else {
+ dev_dbg(dev, "SET-DRP-IE sent. RemainingSpace in beacon "
+ "= %d.\n", result);
+ result = 0;
+ }
+error_cmd:
+ kfree(cmd);
+error:
+ return result;
+
+}
+/**
+ * Send all DRP IEs associated with this host
+ *
+ * @returns: >= 0 number of bytes still available in the beacon
+ * < 0 errno code on error.
+ *
+ * As per the protocol we obtain the host controller device lock to access
+ * bandwidth structures.
+ */
+int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
+{
+ int result;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = uwb_rc_gen_send_drp_ie(rc);
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+void uwb_drp_handle_timeout(struct uwb_rsv *rsv)
+{
+ struct device *dev = &rsv->rc->uwb_dev.dev;
+
+ dev_dbg(dev, "reservation timeout in state %s (%d)\n",
+ uwb_rsv_state_str(rsv->state), rsv->state);
+
+ switch (rsv->state) {
+ case UWB_RSV_STATE_O_INITIATED:
+ if (rsv->is_multicast) {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+ return;
+ }
+ break;
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ if (rsv->is_multicast)
+ return;
+ break;
+ default:
+ break;
+ }
+ uwb_rsv_remove(rsv);
+}
+
+/*
+ * Based on the DRP IE, transition a target reservation to a new
+ * state.
+ */
+static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ int status;
+ enum uwb_drp_reason reason_code;
+
+ status = uwb_ie_drp_status(drp_ie);
+ reason_code = uwb_ie_drp_reason_code(drp_ie);
+
+ if (status) {
+ switch (reason_code) {
+ case UWB_DRP_REASON_ACCEPTED:
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
+ break;
+ case UWB_DRP_REASON_MODIFIED:
+ dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n",
+ reason_code, status);
+ break;
+ default:
+ dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+ reason_code, status);
+ }
+ } else {
+ switch (reason_code) {
+ case UWB_DRP_REASON_ACCEPTED:
+ /* New reservations are handled in uwb_rsv_find(). */
+ break;
+ case UWB_DRP_REASON_DENIED:
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+ break;
+ case UWB_DRP_REASON_CONFLICT:
+ case UWB_DRP_REASON_MODIFIED:
+ dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n",
+ reason_code, status);
+ break;
+ default:
+ dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+ reason_code, status);
+ }
+ }
+}
+
+/*
+ * Based on the DRP IE, transition an owner reservation to a new
+ * state.
+ */
+static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ int status;
+ enum uwb_drp_reason reason_code;
+
+ status = uwb_ie_drp_status(drp_ie);
+ reason_code = uwb_ie_drp_reason_code(drp_ie);
+
+ if (status) {
+ switch (reason_code) {
+ case UWB_DRP_REASON_ACCEPTED:
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+ break;
+ case UWB_DRP_REASON_MODIFIED:
+ dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n",
+ reason_code, status);
+ break;
+ default:
+ dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+ reason_code, status);
+ }
+ } else {
+ switch (reason_code) {
+ case UWB_DRP_REASON_PENDING:
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING);
+ break;
+ case UWB_DRP_REASON_DENIED:
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+ break;
+ case UWB_DRP_REASON_CONFLICT:
+ case UWB_DRP_REASON_MODIFIED:
+ dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n",
+ reason_code, status);
+ break;
+ default:
+ dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+ reason_code, status);
+ }
+ }
+}
+
+/*
+ * Process a received DRP IE, it's either for a reservation owned by
+ * the RC or targeted at it (or it's for a WUSB cluster reservation).
+ */
+static void uwb_drp_process(struct uwb_rc *rc, struct uwb_dev *src,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct uwb_rsv *rsv;
+
+ rsv = uwb_rsv_find(rc, src, drp_ie);
+ if (!rsv) {
+ /*
+ * No reservation? It's either for a recently
+ * terminated reservation; or the DRP IE couldn't be
+ * processed (e.g., an invalid IE or out of memory).
+ */
+ return;
+ }
+
+ /*
+ * Do nothing with DRP IEs for reservations that have been
+ * terminated.
+ */
+ if (rsv->state == UWB_RSV_STATE_NONE) {
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+ return;
+ }
+
+ if (uwb_ie_drp_owner(drp_ie))
+ uwb_drp_process_target(rc, rsv, drp_ie);
+ else
+ uwb_drp_process_owner(rc, rsv, drp_ie);
+}
+
+
+/*
+ * Process all the DRP IEs (both DRP IEs and the DRP Availability IE)
+ * from a device.
+ */
+static
+void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
+ size_t ielen, struct uwb_dev *src_dev)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_ie_hdr *ie_hdr;
+ void *ptr;
+
+ ptr = drp_evt->ie_data;
+ for (;;) {
+ ie_hdr = uwb_ie_next(&ptr, &ielen);
+ if (!ie_hdr)
+ break;
+
+ switch (ie_hdr->element_id) {
+ case UWB_IE_DRP_AVAILABILITY:
+ /* FIXME: does something need to be done with this? */
+ break;
+ case UWB_IE_DRP:
+ uwb_drp_process(rc, src_dev, (struct uwb_ie_drp *)ie_hdr);
+ break;
+ default:
+ dev_warn(dev, "unexpected IE in DRP notification\n");
+ break;
+ }
+ }
+
+ if (ielen > 0)
+ dev_warn(dev, "%d octets remaining in DRP notification\n",
+ (int)ielen);
+}
+
+
+/*
+ * Go through all the DRP IEs and find the ones that conflict with our
+ * reservations.
+ *
+ * FIXME: must resolve the conflict according the the rules in
+ * [ECMA-368].
+ */
+static
+void uwb_drp_process_conflict_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
+ size_t ielen, struct uwb_dev *src_dev)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_ie_hdr *ie_hdr;
+ struct uwb_ie_drp *drp_ie;
+ void *ptr;
+
+ ptr = drp_evt->ie_data;
+ for (;;) {
+ ie_hdr = uwb_ie_next(&ptr, &ielen);
+ if (!ie_hdr)
+ break;
+
+ drp_ie = container_of(ie_hdr, struct uwb_ie_drp, hdr);
+
+ /* FIXME: check if this DRP IE conflicts. */
+ }
+
+ if (ielen > 0)
+ dev_warn(dev, "%d octets remaining in DRP notification\n",
+ (int)ielen);
+}
+
+
+/*
+ * Terminate all reservations owned by, or targeted at, 'uwb_dev'.
+ */
+static void uwb_drp_terminate_all(struct uwb_rc *rc, struct uwb_dev *uwb_dev)
+{
+ struct uwb_rsv *rsv;
+
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ if (rsv->owner == uwb_dev
+ || (rsv->target.type == UWB_RSV_TARGET_DEV && rsv->target.dev == uwb_dev))
+ uwb_rsv_remove(rsv);
+ }
+}
+
+
+/**
+ * uwbd_evt_handle_rc_drp - handle a DRP_IE event
+ * @evt: the DRP_IE event from the radio controller
+ *
+ * This processes DRP notifications from the radio controller, either
+ * initiating a new reservation or transitioning an existing
+ * reservation into a different state.
+ *
+ * DRP notifications can occur for three different reasons:
+ *
+ * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as
+ * the target or source have been recieved.
+ *
+ * These DRP IEs could be new or for an existing reservation.
+ *
+ * If the DRP IE for an existing reservation ceases to be to
+ * recieved for at least mMaxLostBeacons, the reservation should be
+ * considered to be terminated. Note that the TERMINATE reason (see
+ * below) may not always be signalled (e.g., the remote device has
+ * two or more reservations established with the RC).
+ *
+ * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon
+ * group conflict with the RC's reservations.
+ *
+ * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received
+ * from a device (i.e., it's terminated all reservations).
+ *
+ * Only the software state of the reservations is changed; the setting
+ * of the radio controller's DRP IEs is done after all the events in
+ * an event buffer are processed. This saves waiting multiple times
+ * for the SET_DRP_IE command to complete.
+ */
+int uwbd_evt_handle_rc_drp(struct uwb_event *evt)
+{
+ struct device *dev = &evt->rc->uwb_dev.dev;
+ struct uwb_rc *rc = evt->rc;
+ struct uwb_rc_evt_drp *drp_evt;
+ size_t ielength, bytes_left;
+ struct uwb_dev_addr src_addr;
+ struct uwb_dev *src_dev;
+ int reason;
+
+ /* Is there enough data to decode the event (and any IEs in
+ its payload)? */
+ if (evt->notif.size < sizeof(*drp_evt)) {
+ dev_err(dev, "DRP event: Not enough data to decode event "
+ "[%zu bytes left, %zu needed]\n",
+ evt->notif.size, sizeof(*drp_evt));
+ return 0;
+ }
+ bytes_left = evt->notif.size - sizeof(*drp_evt);
+ drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb);
+ ielength = le16_to_cpu(drp_evt->ie_length);
+ if (bytes_left != ielength) {
+ dev_err(dev, "DRP event: Not enough data in payload [%zu"
+ "bytes left, %zu declared in the event]\n",
+ bytes_left, ielength);
+ return 0;
+ }
+
+ memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr));
+ src_dev = uwb_dev_get_by_devaddr(rc, &src_addr);
+ if (!src_dev) {
+ /*
+ * A DRP notification from an unrecognized device.
+ *
+ * This is probably from a WUSB device that doesn't
+ * have an EUI-48 and therefore doesn't show up in the
+ * UWB device database. It's safe to simply ignore
+ * these.
+ */
+ return 0;
+ }
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ reason = uwb_rc_evt_drp_reason(drp_evt);
+
+ switch (reason) {
+ case UWB_DRP_NOTIF_DRP_IE_RCVD:
+ uwb_drp_process_all(rc, drp_evt, ielength, src_dev);
+ break;
+ case UWB_DRP_NOTIF_CONFLICT:
+ uwb_drp_process_conflict_all(rc, drp_evt, ielength, src_dev);
+ break;
+ case UWB_DRP_NOTIF_TERMINATE:
+ uwb_drp_terminate_all(rc, src_dev);
+ break;
+ default:
+ dev_warn(dev, "ignored DRP event with reason code: %d\n", reason);
+ break;
+ }
+
+ mutex_unlock(&rc->rsvs_mutex);
+
+ uwb_dev_put(src_dev);
+ return 0;
+}
diff --git a/drivers/uwb/est.c b/drivers/uwb/est.c
new file mode 100644
index 00000000000..5fe566b7c84
--- /dev/null
+++ b/drivers/uwb/est.c
@@ -0,0 +1,477 @@
+/*
+ * Ultra Wide Band Radio Control
+ * Event Size Tables management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ *
+ * Infrastructure, code and data tables for guessing the size of
+ * events received on the notification endpoints of UWB radio
+ * controllers.
+ *
+ * You define a table of events and for each, its size and how to get
+ * the extra size.
+ *
+ * ENTRY POINTS:
+ *
+ * uwb_est_{init/destroy}(): To initialize/release the EST subsystem.
+ *
+ * uwb_est_[u]register(): To un/register event size tables
+ * uwb_est_grow()
+ *
+ * uwb_est_find_size(): Get the size of an event
+ * uwb_est_get_size()
+ */
+#include <linux/spinlock.h>
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+#include "uwb-internal.h"
+
+
+struct uwb_est {
+ u16 type_event_high;
+ u16 vendor, product;
+ u8 entries;
+ const struct uwb_est_entry *entry;
+};
+
+
+static struct uwb_est *uwb_est;
+static u8 uwb_est_size;
+static u8 uwb_est_used;
+static DEFINE_RWLOCK(uwb_est_lock);
+
+/**
+ * WUSB Standard Event Size Table, HWA-RC interface
+ *
+ * Sizes for events and notifications type 0 (general), high nibble 0.
+ */
+static
+struct uwb_est_entry uwb_est_00_00xx[] = {
+ [UWB_RC_EVT_IE_RCV] = {
+ .size = sizeof(struct uwb_rc_evt_ie_rcv),
+ .offset = 1 + offsetof(struct uwb_rc_evt_ie_rcv, wIELength),
+ },
+ [UWB_RC_EVT_BEACON] = {
+ .size = sizeof(struct uwb_rc_evt_beacon),
+ .offset = 1 + offsetof(struct uwb_rc_evt_beacon, wBeaconInfoLength),
+ },
+ [UWB_RC_EVT_BEACON_SIZE] = {
+ .size = sizeof(struct uwb_rc_evt_beacon_size),
+ },
+ [UWB_RC_EVT_BPOIE_CHANGE] = {
+ .size = sizeof(struct uwb_rc_evt_bpoie_change),
+ .offset = 1 + offsetof(struct uwb_rc_evt_bpoie_change,
+ wBPOIELength),
+ },
+ [UWB_RC_EVT_BP_SLOT_CHANGE] = {
+ .size = sizeof(struct uwb_rc_evt_bp_slot_change),
+ },
+ [UWB_RC_EVT_BP_SWITCH_IE_RCV] = {
+ .size = sizeof(struct uwb_rc_evt_bp_switch_ie_rcv),
+ .offset = 1 + offsetof(struct uwb_rc_evt_bp_switch_ie_rcv, wIELength),
+ },
+ [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
+ .size = sizeof(struct uwb_rc_evt_dev_addr_conflict),
+ },
+ [UWB_RC_EVT_DRP_AVAIL] = {
+ .size = sizeof(struct uwb_rc_evt_drp_avail)
+ },
+ [UWB_RC_EVT_DRP] = {
+ .size = sizeof(struct uwb_rc_evt_drp),
+ .offset = 1 + offsetof(struct uwb_rc_evt_drp, ie_length),
+ },
+ [UWB_RC_EVT_BP_SWITCH_STATUS] = {
+ .size = sizeof(struct uwb_rc_evt_bp_switch_status),
+ },
+ [UWB_RC_EVT_CMD_FRAME_RCV] = {
+ .size = sizeof(struct uwb_rc_evt_cmd_frame_rcv),
+ .offset = 1 + offsetof(struct uwb_rc_evt_cmd_frame_rcv, dataLength),
+ },
+ [UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV] = {
+ .size = sizeof(struct uwb_rc_evt_channel_change_ie_rcv),
+ .offset = 1 + offsetof(struct uwb_rc_evt_channel_change_ie_rcv, wIELength),
+ },
+ [UWB_RC_CMD_CHANNEL_CHANGE] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_DEV_ADDR_MGMT] = {
+ .size = sizeof(struct uwb_rc_evt_dev_addr_mgmt) },
+ [UWB_RC_CMD_GET_IE] = {
+ .size = sizeof(struct uwb_rc_evt_get_ie),
+ .offset = 1 + offsetof(struct uwb_rc_evt_get_ie, wIELength),
+ },
+ [UWB_RC_CMD_RESET] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SCAN] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SET_BEACON_FILTER] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SET_DRP_IE] = {
+ .size = sizeof(struct uwb_rc_evt_set_drp_ie),
+ },
+ [UWB_RC_CMD_SET_IE] = {
+ .size = sizeof(struct uwb_rc_evt_set_ie),
+ },
+ [UWB_RC_CMD_SET_NOTIFICATION_FILTER] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SET_TX_POWER] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SLEEP] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_START_BEACON] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_STOP_BEACON] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_BP_MERGE] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SEND_COMMAND_FRAME] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+ [UWB_RC_CMD_SET_ASIE_NOTIF] = {
+ .size = sizeof(struct uwb_rc_evt_confirm),
+ },
+};
+
+static
+struct uwb_est_entry uwb_est_01_00xx[] = {
+ [UWB_RC_DAA_ENERGY_DETECTED] = {
+ .size = sizeof(struct uwb_rc_evt_daa_energy_detected),
+ },
+ [UWB_RC_SET_DAA_ENERGY_MASK] = {
+ .size = sizeof(struct uwb_rc_evt_set_daa_energy_mask),
+ },
+ [UWB_RC_SET_NOTIFICATION_FILTER_EX] = {
+ .size = sizeof(struct uwb_rc_evt_set_notification_filter_ex),
+ },
+};
+
+/**
+ * Initialize the EST subsystem
+ *
+ * Register the standard tables also.
+ *
+ * FIXME: tag init
+ */
+int uwb_est_create(void)
+{
+ int result;
+
+ uwb_est_size = 2;
+ uwb_est_used = 0;
+ uwb_est = kzalloc(uwb_est_size * sizeof(uwb_est[0]), GFP_KERNEL);
+ if (uwb_est == NULL)
+ return -ENOMEM;
+
+ result = uwb_est_register(UWB_RC_CET_GENERAL, 0, 0xffff, 0xffff,
+ uwb_est_00_00xx, ARRAY_SIZE(uwb_est_00_00xx));
+ if (result < 0)
+ goto out;
+ result = uwb_est_register(UWB_RC_CET_EX_TYPE_1, 0, 0xffff, 0xffff,
+ uwb_est_01_00xx, ARRAY_SIZE(uwb_est_01_00xx));
+out:
+ return result;
+}
+
+
+/** Clean it up */
+void uwb_est_destroy(void)
+{
+ kfree(uwb_est);
+ uwb_est = NULL;
+ uwb_est_size = uwb_est_used = 0;
+}
+
+
+/**
+ * Double the capacity of the EST table
+ *
+ * @returns 0 if ok, < 0 errno no error.
+ */
+static
+int uwb_est_grow(void)
+{
+ size_t actual_size = uwb_est_size * sizeof(uwb_est[0]);
+ void *new = kmalloc(2 * actual_size, GFP_ATOMIC);
+ if (new == NULL)
+ return -ENOMEM;
+ memcpy(new, uwb_est, actual_size);
+ memset(new + actual_size, 0, actual_size);
+ kfree(uwb_est);
+ uwb_est = new;
+ uwb_est_size *= 2;
+ return 0;
+}
+
+
+/**
+ * Register an event size table
+ *
+ * Makes room for it if the table is full, and then inserts it in the
+ * right position (entries are sorted by type, event_high, vendor and
+ * then product).
+ *
+ * @vendor: vendor code for matching against the device (0x0000 and
+ * 0xffff mean any); use 0x0000 to force all to match without
+ * checking possible vendor specific ones, 0xfffff to match
+ * after checking vendor specific ones.
+ *
+ * @product: product code from that vendor; same matching rules, use
+ * 0x0000 for not allowing vendor specific matches, 0xffff
+ * for allowing.
+ *
+ * This arragement just makes the tables sort differenty. Because the
+ * table is sorted by growing type-event_high-vendor-product, a zero
+ * vendor will match before than a 0x456a vendor, that will match
+ * before a 0xfffff vendor.
+ *
+ * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
+ */
+/* FIXME: add bus type to vendor/product code */
+int uwb_est_register(u8 type, u8 event_high, u16 vendor, u16 product,
+ const struct uwb_est_entry *entry, size_t entries)
+{
+ unsigned long flags;
+ unsigned itr;
+ u16 type_event_high;
+ int result = 0;
+
+ write_lock_irqsave(&uwb_est_lock, flags);
+ if (uwb_est_used == uwb_est_size) {
+ result = uwb_est_grow();
+ if (result < 0)
+ goto out;
+ }
+ /* Find the right spot to insert it in */
+ type_event_high = type << 8 | event_high;
+ for (itr = 0; itr < uwb_est_used; itr++)
+ if (uwb_est[itr].type_event_high < type
+ && uwb_est[itr].vendor < vendor
+ && uwb_est[itr].product < product)
+ break;
+
+ /* Shift others to make room for the new one? */
+ if (itr < uwb_est_used)
+ memmove(&uwb_est[itr+1], &uwb_est[itr], uwb_est_used - itr);
+ uwb_est[itr].type_event_high = type << 8 | event_high;
+ uwb_est[itr].vendor = vendor;
+ uwb_est[itr].product = product;
+ uwb_est[itr].entry = entry;
+ uwb_est[itr].entries = entries;
+ uwb_est_used++;
+out:
+ write_unlock_irqrestore(&uwb_est_lock, flags);
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_est_register);
+
+
+/**
+ * Unregister an event size table
+ *
+ * This just removes the specified entry and moves the ones after it
+ * to fill in the gap. This is needed to keep the list sorted; no
+ * reallocation is done to reduce the size of the table.
+ *
+ * We unregister by all the data we used to register instead of by
+ * pointer to the @entry array because we might have used the same
+ * table for a bunch of IDs (for example).
+ *
+ * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
+ */
+int uwb_est_unregister(u8 type, u8 event_high, u16 vendor, u16 product,
+ const struct uwb_est_entry *entry, size_t entries)
+{
+ unsigned long flags;
+ unsigned itr;
+ struct uwb_est est_cmp = {
+ .type_event_high = type << 8 | event_high,
+ .vendor = vendor,
+ .product = product,
+ .entry = entry,
+ .entries = entries
+ };
+ write_lock_irqsave(&uwb_est_lock, flags);
+ for (itr = 0; itr < uwb_est_used; itr++)
+ if (!memcmp(&uwb_est[itr], &est_cmp, sizeof(est_cmp)))
+ goto found;
+ write_unlock_irqrestore(&uwb_est_lock, flags);
+ return -ENOENT;
+
+found:
+ if (itr < uwb_est_used - 1) /* Not last one? move ones above */
+ memmove(&uwb_est[itr], &uwb_est[itr+1], uwb_est_used - itr - 1);
+ uwb_est_used--;
+ write_unlock_irqrestore(&uwb_est_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_est_unregister);
+
+
+/**
+ * Get the size of an event from a table
+ *
+ * @rceb: pointer to the buffer with the event
+ * @rceb_size: size of the area pointed to by @rceb in bytes.
+ * @returns: > 0 Size of the event
+ * -ENOSPC An area big enough was not provided to look
+ * ahead into the event's guts and guess the size.
+ * -EINVAL Unknown event code (wEvent).
+ *
+ * This will look at the received RCEB and guess what is the total
+ * size. For variable sized events, it will look further ahead into
+ * their length field to see how much data should be read.
+ *
+ * Note this size is *not* final--the neh (Notification/Event Handle)
+ * might specificy an extra size to add.
+ */
+static
+ssize_t uwb_est_get_size(struct uwb_rc *uwb_rc, struct uwb_est *est,
+ u8 event_low, const struct uwb_rceb *rceb,
+ size_t rceb_size)
+{
+ unsigned offset;
+ ssize_t size;
+ struct device *dev = &uwb_rc->uwb_dev.dev;
+ const struct uwb_est_entry *entry;
+
+ size = -ENOENT;
+ if (event_low >= est->entries) { /* in range? */
+ dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u out of range\n",
+ est, est->type_event_high, est->vendor, est->product,
+ est->entries, event_low);
+ goto out;
+ }
+ size = -ENOENT;
+ entry = &est->entry[event_low];
+ if (entry->size == 0 && entry->offset == 0) { /* unknown? */
+ dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u unknown\n",
+ est, est->type_event_high, est->vendor, est->product,
+ est->entries, event_low);
+ goto out;
+ }
+ offset = entry->offset; /* extra fries with that? */
+ if (offset == 0)
+ size = entry->size;
+ else {
+ /* Ops, got an extra size field at 'offset'--read it */
+ const void *ptr = rceb;
+ size_t type_size = 0;
+ offset--;
+ size = -ENOSPC; /* enough data for more? */
+ switch (entry->type) {
+ case UWB_EST_16: type_size = sizeof(__le16); break;
+ case UWB_EST_8: type_size = sizeof(u8); break;
+ default: BUG();
+ }
+ if (offset + type_size > rceb_size) {
+ dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: "
+ "not enough data to read extra size\n",
+ est, est->type_event_high, est->vendor,
+ est->product, est->entries);
+ goto out;
+ }
+ size = entry->size;
+ ptr += offset;
+ switch (entry->type) {
+ case UWB_EST_16: size += le16_to_cpu(*(__le16 *)ptr); break;
+ case UWB_EST_8: size += *(u8 *)ptr; break;
+ default: BUG();
+ }
+ }
+out:
+ return size;
+}
+
+
+/**
+ * Guesses the size of a WA event
+ *
+ * @rceb: pointer to the buffer with the event
+ * @rceb_size: size of the area pointed to by @rceb in bytes.
+ * @returns: > 0 Size of the event
+ * -ENOSPC An area big enough was not provided to look
+ * ahead into the event's guts and guess the size.
+ * -EINVAL Unknown event code (wEvent).
+ *
+ * This will look at the received RCEB and guess what is the total
+ * size by checking all the tables registered with
+ * uwb_est_register(). For variable sized events, it will look further
+ * ahead into their length field to see how much data should be read.
+ *
+ * Note this size is *not* final--the neh (Notification/Event Handle)
+ * might specificy an extra size to add or replace.
+ */
+ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
+ size_t rceb_size)
+{
+ /* FIXME: add vendor/product data */
+ ssize_t size;
+ struct device *dev = &rc->uwb_dev.dev;
+ unsigned long flags;
+ unsigned itr;
+ u16 type_event_high, event;
+ u8 *ptr = (u8 *) rceb;
+
+ read_lock_irqsave(&uwb_est_lock, flags);
+ d_printf(2, dev, "Size query for event 0x%02x/%04x/%02x,"
+ " buffer size %ld\n",
+ (unsigned) rceb->bEventType,
+ (unsigned) le16_to_cpu(rceb->wEvent),
+ (unsigned) rceb->bEventContext,
+ (long) rceb_size);
+ size = -ENOSPC;
+ if (rceb_size < sizeof(*rceb))
+ goto out;
+ event = le16_to_cpu(rceb->wEvent);
+ type_event_high = rceb->bEventType << 8 | (event & 0xff00) >> 8;
+ for (itr = 0; itr < uwb_est_used; itr++) {
+ d_printf(3, dev, "Checking EST 0x%04x/%04x/%04x\n",
+ uwb_est[itr].type_event_high, uwb_est[itr].vendor,
+ uwb_est[itr].product);
+ if (uwb_est[itr].type_event_high != type_event_high)
+ continue;
+ size = uwb_est_get_size(rc, &uwb_est[itr],
+ event & 0x00ff, rceb, rceb_size);
+ /* try more tables that might handle the same type */
+ if (size != -ENOENT)
+ goto out;
+ }
+ dev_dbg(dev, "event 0x%02x/%04x/%02x: no handlers available; "
+ "RCEB %02x %02x %02x %02x\n",
+ (unsigned) rceb->bEventType,
+ (unsigned) le16_to_cpu(rceb->wEvent),
+ (unsigned) rceb->bEventContext,
+ ptr[0], ptr[1], ptr[2], ptr[3]);
+ size = -ENOENT;
+out:
+ read_unlock_irqrestore(&uwb_est_lock, flags);
+ return size;
+}
+EXPORT_SYMBOL_GPL(uwb_est_find_size);
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c
new file mode 100644
index 00000000000..3d26fa0f8ae
--- /dev/null
+++ b/drivers/uwb/hwa-rc.c
@@ -0,0 +1,926 @@
+/*
+ * WUSB Host Wire Adapter: Radio Control Interface (WUSB[8.6])
+ * Radio Control command/event transport
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * Initialize the Radio Control interface Driver.
+ *
+ * For each device probed, creates an 'struct hwarc' which contains
+ * just the representation of the UWB Radio Controller, and the logic
+ * for reading notifications and passing them to the UWB Core.
+ *
+ * So we initialize all of those, register the UWB Radio Controller
+ * and setup the notification/event handle to pipe the notifications
+ * to the UWB management Daemon.
+ *
+ * Command and event filtering.
+ *
+ * This is the driver for the Radio Control Interface described in WUSB
+ * 1.0. The core UWB module assumes that all drivers are compliant to the
+ * WHCI 0.95 specification. We thus create a filter that parses all
+ * incoming messages from the (WUSB 1.0) device and manipulate them to
+ * conform to the WHCI 0.95 specification. Similarly, outgoing messages
+ * are parsed and manipulated to conform to the WUSB 1.0 compliant messages
+ * that the device expects. Only a few messages are affected:
+ * Affected events:
+ * UWB_RC_EVT_BEACON
+ * UWB_RC_EVT_BP_SLOT_CHANGE
+ * UWB_RC_EVT_DRP_AVAIL
+ * UWB_RC_EVT_DRP
+ * Affected commands:
+ * UWB_RC_CMD_SCAN
+ * UWB_RC_CMD_SET_DRP_IE
+ *
+ *
+ *
+ */
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/wusb.h>
+#include <linux/usb/wusb-wa.h>
+#include <linux/uwb.h>
+#include "uwb-internal.h"
+#define D_LOCAL 1
+#include <linux/uwb/debug.h>
+
+/* The device uses commands and events from the WHCI specification, although
+ * reporting itself as WUSB compliant. */
+#define WUSB_QUIRK_WHCI_CMD_EVT 0x01
+
+/**
+ * Descriptor for an instance of the UWB Radio Control Driver that
+ * attaches to the RCI interface of the Host Wired Adapter.
+ *
+ * Unless there is a lock specific to the 'data members', all access
+ * is protected by uwb_rc->mutex.
+ *
+ * The NEEP (Notification/Event EndPoint) URB (@neep_urb) writes to
+ * @rd_buffer. Note there is no locking because it is perfectly (heh!)
+ * serialized--probe() submits an URB, callback is called, processes
+ * the data (synchronously), submits another URB, and so on. There is
+ * no concurrent access to the buffer.
+ */
+struct hwarc {
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+ struct uwb_rc *uwb_rc; /* UWB host controller */
+ struct urb *neep_urb; /* Notification endpoint handling */
+ struct edc neep_edc;
+ void *rd_buffer; /* NEEP read buffer */
+};
+
+
+/* Beacon received notification (WUSB 1.0 [8.6.3.2]) */
+struct uwb_rc_evt_beacon_WUSB_0100 {
+ struct uwb_rceb rceb;
+ u8 bChannelNumber;
+ __le16 wBPSTOffset;
+ u8 bLQI;
+ u8 bRSSI;
+ __le16 wBeaconInfoLength;
+ u8 BeaconInfo[];
+} __attribute__((packed));
+
+/**
+ * Filter WUSB 1.0 BEACON RCV notification to be WHCI 0.95
+ *
+ * @header: the incoming event
+ * @buf_size: size of buffer containing incoming event
+ * @new_size: size of event after filtering completed
+ *
+ * The WHCI 0.95 spec has a "Beacon Type" field. This value is unknown at
+ * the time we receive the beacon from WUSB so we just set it to
+ * UWB_RC_BEACON_TYPE_NEIGHBOR as a default.
+ * The solution below allocates memory upon receipt of every beacon from a
+ * WUSB device. This will deteriorate performance. What is the right way to
+ * do this?
+ */
+static
+int hwarc_filter_evt_beacon_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rceb **header,
+ const size_t buf_size,
+ size_t *new_size)
+{
+ struct uwb_rc_evt_beacon_WUSB_0100 *be;
+ struct uwb_rc_evt_beacon *newbe;
+ size_t bytes_left, ielength;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ be = container_of(*header, struct uwb_rc_evt_beacon_WUSB_0100, rceb);
+ bytes_left = buf_size;
+ if (bytes_left < sizeof(*be)) {
+ dev_err(dev, "Beacon Received Notification: Not enough data "
+ "to decode for filtering (%zu vs %zu bytes needed)\n",
+ bytes_left, sizeof(*be));
+ return -EINVAL;
+ }
+ bytes_left -= sizeof(*be);
+ ielength = le16_to_cpu(be->wBeaconInfoLength);
+ if (bytes_left < ielength) {
+ dev_err(dev, "Beacon Received Notification: Not enough data "
+ "to decode IEs (%zu vs %zu bytes needed)\n",
+ bytes_left, ielength);
+ return -EINVAL;
+ }
+ newbe = kzalloc(sizeof(*newbe) + ielength, GFP_ATOMIC);
+ if (newbe == NULL)
+ return -ENOMEM;
+ newbe->rceb = be->rceb;
+ newbe->bChannelNumber = be->bChannelNumber;
+ newbe->bBeaconType = UWB_RC_BEACON_TYPE_NEIGHBOR;
+ newbe->wBPSTOffset = be->wBPSTOffset;
+ newbe->bLQI = be->bLQI;
+ newbe->bRSSI = be->bRSSI;
+ newbe->wBeaconInfoLength = be->wBeaconInfoLength;
+ memcpy(newbe->BeaconInfo, be->BeaconInfo, ielength);
+ *header = &newbe->rceb;
+ *new_size = sizeof(*newbe) + ielength;
+ return 1; /* calling function will free memory */
+}
+
+
+/* DRP Availability change notification (WUSB 1.0 [8.6.3.8]) */
+struct uwb_rc_evt_drp_avail_WUSB_0100 {
+ struct uwb_rceb rceb;
+ __le16 wIELength;
+ u8 IEData[];
+} __attribute__((packed));
+
+/**
+ * Filter WUSB 1.0 DRP AVAILABILITY CHANGE notification to be WHCI 0.95
+ *
+ * @header: the incoming event
+ * @buf_size: size of buffer containing incoming event
+ * @new_size: size of event after filtering completed
+ */
+static
+int hwarc_filter_evt_drp_avail_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rceb **header,
+ const size_t buf_size,
+ size_t *new_size)
+{
+ struct uwb_rc_evt_drp_avail_WUSB_0100 *da;
+ struct uwb_rc_evt_drp_avail *newda;
+ struct uwb_ie_hdr *ie_hdr;
+ size_t bytes_left, ielength;
+ struct device *dev = &rc->uwb_dev.dev;
+
+
+ da = container_of(*header, struct uwb_rc_evt_drp_avail_WUSB_0100, rceb);
+ bytes_left = buf_size;
+ if (bytes_left < sizeof(*da)) {
+ dev_err(dev, "Not enough data to decode DRP Avail "
+ "Notification for filtering. Expected %zu, "
+ "received %zu.\n", (size_t)sizeof(*da), bytes_left);
+ return -EINVAL;
+ }
+ bytes_left -= sizeof(*da);
+ ielength = le16_to_cpu(da->wIELength);
+ if (bytes_left < ielength) {
+ dev_err(dev, "DRP Avail Notification filter: IE length "
+ "[%zu bytes] does not match actual length "
+ "[%zu bytes].\n", ielength, bytes_left);
+ return -EINVAL;
+ }
+ if (ielength < sizeof(*ie_hdr)) {
+ dev_err(dev, "DRP Avail Notification filter: Not enough "
+ "data to decode IE [%zu bytes, %zu needed]\n",
+ ielength, sizeof(*ie_hdr));
+ return -EINVAL;
+ }
+ ie_hdr = (void *) da->IEData;
+ if (ie_hdr->length > 32) {
+ dev_err(dev, "DRP Availability Change event has unexpected "
+ "length for filtering. Expected < 32 bytes, "
+ "got %zu bytes.\n", (size_t)ie_hdr->length);
+ return -EINVAL;
+ }
+ newda = kzalloc(sizeof(*newda), GFP_ATOMIC);
+ if (newda == NULL)
+ return -ENOMEM;
+ newda->rceb = da->rceb;
+ memcpy(newda->bmp, (u8 *) ie_hdr + sizeof(*ie_hdr), ie_hdr->length);
+ *header = &newda->rceb;
+ *new_size = sizeof(*newda);
+ return 1; /* calling function will free memory */
+}
+
+
+/* DRP notification (WUSB 1.0 [8.6.3.9]) */
+struct uwb_rc_evt_drp_WUSB_0100 {
+ struct uwb_rceb rceb;
+ struct uwb_dev_addr wSrcAddr;
+ u8 bExplicit;
+ __le16 wIELength;
+ u8 IEData[];
+} __attribute__((packed));
+
+/**
+ * Filter WUSB 1.0 DRP Notification to be WHCI 0.95
+ *
+ * @header: the incoming event
+ * @buf_size: size of buffer containing incoming event
+ * @new_size: size of event after filtering completed
+ *
+ * It is hard to manage DRP reservations without having a Reason code.
+ * Unfortunately there is none in the WUSB spec. We just set the default to
+ * DRP IE RECEIVED.
+ * We do not currently use the bBeaconSlotNumber value, so we set this to
+ * zero for now.
+ */
+static
+int hwarc_filter_evt_drp_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rceb **header,
+ const size_t buf_size,
+ size_t *new_size)
+{
+ struct uwb_rc_evt_drp_WUSB_0100 *drpev;
+ struct uwb_rc_evt_drp *newdrpev;
+ size_t bytes_left, ielength;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ drpev = container_of(*header, struct uwb_rc_evt_drp_WUSB_0100, rceb);
+ bytes_left = buf_size;
+ if (bytes_left < sizeof(*drpev)) {
+ dev_err(dev, "Not enough data to decode DRP Notification "
+ "for filtering. Expected %zu, received %zu.\n",
+ (size_t)sizeof(*drpev), bytes_left);
+ return -EINVAL;
+ }
+ ielength = le16_to_cpu(drpev->wIELength);
+ bytes_left -= sizeof(*drpev);
+ if (bytes_left < ielength) {
+ dev_err(dev, "DRP Notification filter: header length [%zu "
+ "bytes] does not match actual length [%zu "
+ "bytes].\n", ielength, bytes_left);
+ return -EINVAL;
+ }
+ newdrpev = kzalloc(sizeof(*newdrpev) + ielength, GFP_ATOMIC);
+ if (newdrpev == NULL)
+ return -ENOMEM;
+ newdrpev->rceb = drpev->rceb;
+ newdrpev->src_addr = drpev->wSrcAddr;
+ newdrpev->reason = UWB_DRP_NOTIF_DRP_IE_RCVD;
+ newdrpev->beacon_slot_number = 0;
+ newdrpev->ie_length = drpev->wIELength;
+ memcpy(newdrpev->ie_data, drpev->IEData, ielength);
+ *header = &newdrpev->rceb;
+ *new_size = sizeof(*newdrpev) + ielength;
+ return 1; /* calling function will free memory */
+}
+
+
+/* Scan Command (WUSB 1.0 [8.6.2.5]) */
+struct uwb_rc_cmd_scan_WUSB_0100 {
+ struct uwb_rccb rccb;
+ u8 bChannelNumber;
+ u8 bScanState;
+} __attribute__((packed));
+
+/**
+ * Filter WHCI 0.95 SCAN command to be WUSB 1.0 SCAN command
+ *
+ * @header: command sent to device (compliant to WHCI 0.95)
+ * @size: size of command sent to device
+ *
+ * We only reduce the size by two bytes because the WUSB 1.0 scan command
+ * does not have the last field (wStarttime). Also, make sure we don't send
+ * the device an unexpected scan type.
+ */
+static
+int hwarc_filter_cmd_scan_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rccb **header,
+ size_t *size)
+{
+ struct uwb_rc_cmd_scan *sc;
+
+ sc = container_of(*header, struct uwb_rc_cmd_scan, rccb);
+
+ if (sc->bScanState == UWB_SCAN_ONLY_STARTTIME)
+ sc->bScanState = UWB_SCAN_ONLY;
+ /* Don't send the last two bytes. */
+ *size -= 2;
+ return 0;
+}
+
+
+/* SET DRP IE command (WUSB 1.0 [8.6.2.7]) */
+struct uwb_rc_cmd_set_drp_ie_WUSB_0100 {
+ struct uwb_rccb rccb;
+ u8 bExplicit;
+ __le16 wIELength;
+ struct uwb_ie_drp IEData[];
+} __attribute__((packed));
+
+/**
+ * Filter WHCI 0.95 SET DRP IE command to be WUSB 1.0 SET DRP IE command
+ *
+ * @header: command sent to device (compliant to WHCI 0.95)
+ * @size: size of command sent to device
+ *
+ * WUSB has an extra bExplicit field - we assume always explicit
+ * negotiation so this field is set. The command expected by the device is
+ * thus larger than the one prepared by the driver so we need to
+ * reallocate memory to accommodate this.
+ * We trust the driver to send us the correct data so no checking is done
+ * on incoming data - evn though it is variable length.
+ */
+static
+int hwarc_filter_cmd_set_drp_ie_WUSB_0100(struct uwb_rc *rc,
+ struct uwb_rccb **header,
+ size_t *size)
+{
+ struct uwb_rc_cmd_set_drp_ie *orgcmd;
+ struct uwb_rc_cmd_set_drp_ie_WUSB_0100 *cmd;
+ size_t ielength;
+
+ orgcmd = container_of(*header, struct uwb_rc_cmd_set_drp_ie, rccb);
+ ielength = le16_to_cpu(orgcmd->wIELength);
+ cmd = kzalloc(sizeof(*cmd) + ielength, GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+ cmd->rccb = orgcmd->rccb;
+ cmd->bExplicit = 0;
+ cmd->wIELength = orgcmd->wIELength;
+ memcpy(cmd->IEData, orgcmd->IEData, ielength);
+ *header = &cmd->rccb;
+ *size = sizeof(*cmd) + ielength;
+ return 1; /* calling function will free memory */
+}
+
+
+/**
+ * Filter data from WHCI driver to WUSB device
+ *
+ * @header: WHCI 0.95 compliant command from driver
+ * @size: length of command
+ *
+ * The routine managing commands to the device (uwb_rc_cmd()) will call the
+ * filtering function pointer (if it exists) before it passes any data to
+ * the device. At this time the command has been formatted according to
+ * WHCI 0.95 and is ready to be sent to the device.
+ *
+ * The filter function will be provided with the current command and its
+ * length. The function will manipulate the command if necessary and
+ * potentially reallocate memory for a command that needed more memory that
+ * the given command. If new memory was created the function will return 1
+ * to indicate to the calling function that the memory need to be freed
+ * when not needed any more. The size will contain the new length of the
+ * command.
+ * If memory has not been allocated we rely on the original mechanisms to
+ * free the memory of the command - even when we reduce the value of size.
+ */
+static
+int hwarc_filter_cmd_WUSB_0100(struct uwb_rc *rc, struct uwb_rccb **header,
+ size_t *size)
+{
+ int result;
+ struct uwb_rccb *rccb = *header;
+ int cmd = le16_to_cpu(rccb->wCommand);
+ switch (cmd) {
+ case UWB_RC_CMD_SCAN:
+ result = hwarc_filter_cmd_scan_WUSB_0100(rc, header, size);
+ break;
+ case UWB_RC_CMD_SET_DRP_IE:
+ result = hwarc_filter_cmd_set_drp_ie_WUSB_0100(rc, header, size);
+ break;
+ default:
+ result = -ENOANO;
+ break;
+ }
+ return result;
+}
+
+
+/**
+ * Filter data from WHCI driver to WUSB device
+ *
+ * @header: WHCI 0.95 compliant command from driver
+ * @size: length of command
+ *
+ * Filter commands based on which protocol the device supports. The WUSB
+ * errata should be the same as WHCI 0.95 so we do not filter that here -
+ * only WUSB 1.0.
+ */
+static
+int hwarc_filter_cmd(struct uwb_rc *rc, struct uwb_rccb **header,
+ size_t *size)
+{
+ int result = -ENOANO;
+ if (rc->version == 0x0100)
+ result = hwarc_filter_cmd_WUSB_0100(rc, header, size);
+ return result;
+}
+
+
+/**
+ * Compute return value as sum of incoming value and value at given offset
+ *
+ * @rceb: event for which we compute the size, it contains a variable
+ * length field.
+ * @core_size: size of the "non variable" part of the event
+ * @offset: place in event where the length of the variable part is stored
+ * @buf_size: total length of buffer in which event arrived - we need to make
+ * sure we read the offset in memory that is still part of the event
+ */
+static
+ssize_t hwarc_get_event_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
+ size_t core_size, size_t offset,
+ const size_t buf_size)
+{
+ ssize_t size = -ENOSPC;
+ const void *ptr = rceb;
+ size_t type_size = sizeof(__le16);
+ struct device *dev = &rc->uwb_dev.dev;
+
+ if (offset + type_size >= buf_size) {
+ dev_err(dev, "Not enough data to read extra size of event "
+ "0x%02x/%04x/%02x, only got %zu bytes.\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext, buf_size);
+ goto out;
+ }
+ ptr += offset;
+ size = core_size + le16_to_cpu(*(__le16 *)ptr);
+out:
+ return size;
+}
+
+
+/* Beacon slot change notification (WUSB 1.0 [8.6.3.5]) */
+struct uwb_rc_evt_bp_slot_change_WUSB_0100 {
+ struct uwb_rceb rceb;
+ u8 bSlotNumber;
+} __attribute__((packed));
+
+
+/**
+ * Filter data from WUSB device to WHCI driver
+ *
+ * @header: incoming event
+ * @buf_size: size of buffer in which event arrived
+ * @_event_size: actual size of event in the buffer
+ * @new_size: size of event after filtered
+ *
+ * We don't know how the buffer is constructed - there may be more than one
+ * event in it so buffer length does not determine event length. We first
+ * determine the expected size of the incoming event. This value is passed
+ * back only if the actual filtering succeeded (so we know the computed
+ * expected size is correct). This value will be zero if
+ * the event did not need any filtering.
+ *
+ * WHCI interprets the BP Slot Change event's data differently than
+ * WUSB. The event sizes are exactly the same. The data field
+ * indicates the new beacon slot in which a RC is transmitting its
+ * beacon. The maximum value of this is 96 (wMacBPLength ECMA-368
+ * 17.16 (Table 117)). We thus know that the WUSB value will not set
+ * the bit bNoSlot, so we don't really do anything (placeholder).
+ */
+static
+int hwarc_filter_event_WUSB_0100(struct uwb_rc *rc, struct uwb_rceb **header,
+ const size_t buf_size, size_t *_real_size,
+ size_t *_new_size)
+{
+ int result = -ENOANO;
+ struct uwb_rceb *rceb = *header;
+ int event = le16_to_cpu(rceb->wEvent);
+ size_t event_size;
+ size_t core_size, offset;
+
+ if (rceb->bEventType != UWB_RC_CET_GENERAL)
+ goto out;
+ switch (event) {
+ case UWB_RC_EVT_BEACON:
+ core_size = sizeof(struct uwb_rc_evt_beacon_WUSB_0100);
+ offset = offsetof(struct uwb_rc_evt_beacon_WUSB_0100,
+ wBeaconInfoLength);
+ event_size = hwarc_get_event_size(rc, rceb, core_size,
+ offset, buf_size);
+ if (event_size < 0)
+ goto out;
+ *_real_size = event_size;
+ result = hwarc_filter_evt_beacon_WUSB_0100(rc, header,
+ buf_size, _new_size);
+ break;
+ case UWB_RC_EVT_BP_SLOT_CHANGE:
+ *_new_size = *_real_size =
+ sizeof(struct uwb_rc_evt_bp_slot_change_WUSB_0100);
+ result = 0;
+ break;
+
+ case UWB_RC_EVT_DRP_AVAIL:
+ core_size = sizeof(struct uwb_rc_evt_drp_avail_WUSB_0100);
+ offset = offsetof(struct uwb_rc_evt_drp_avail_WUSB_0100,
+ wIELength);
+ event_size = hwarc_get_event_size(rc, rceb, core_size,
+ offset, buf_size);
+ if (event_size < 0)
+ goto out;
+ *_real_size = event_size;
+ result = hwarc_filter_evt_drp_avail_WUSB_0100(
+ rc, header, buf_size, _new_size);
+ break;
+
+ case UWB_RC_EVT_DRP:
+ core_size = sizeof(struct uwb_rc_evt_drp_WUSB_0100);
+ offset = offsetof(struct uwb_rc_evt_drp_WUSB_0100, wIELength);
+ event_size = hwarc_get_event_size(rc, rceb, core_size,
+ offset, buf_size);
+ if (event_size < 0)
+ goto out;
+ *_real_size = event_size;
+ result = hwarc_filter_evt_drp_WUSB_0100(rc, header,
+ buf_size, _new_size);
+ break;
+
+ default:
+ break;
+ }
+out:
+ return result;
+}
+
+/**
+ * Filter data from WUSB device to WHCI driver
+ *
+ * @header: incoming event
+ * @buf_size: size of buffer in which event arrived
+ * @_event_size: actual size of event in the buffer
+ * @_new_size: size of event after filtered
+ *
+ * Filter events based on which protocol the device supports. The WUSB
+ * errata should be the same as WHCI 0.95 so we do not filter that here -
+ * only WUSB 1.0.
+ *
+ * If we don't handle it, we return -ENOANO (why the weird error code?
+ * well, so if I get it, I can pinpoint in the code that raised
+ * it...after all, not too many places use the higher error codes).
+ */
+static
+int hwarc_filter_event(struct uwb_rc *rc, struct uwb_rceb **header,
+ const size_t buf_size, size_t *_real_size,
+ size_t *_new_size)
+{
+ int result = -ENOANO;
+ if (rc->version == 0x0100)
+ result = hwarc_filter_event_WUSB_0100(
+ rc, header, buf_size, _real_size, _new_size);
+ return result;
+}
+
+
+/**
+ * Execute an UWB RC command on HWA
+ *
+ * @rc: Instance of a Radio Controller that is a HWA
+ * @cmd: Buffer containing the RCCB and payload to execute
+ * @cmd_size: Size of the command buffer.
+ *
+ * NOTE: rc's mutex has to be locked
+ */
+static
+int hwarc_cmd(struct uwb_rc *uwb_rc, const struct uwb_rccb *cmd, size_t cmd_size)
+{
+ struct hwarc *hwarc = uwb_rc->priv;
+ return usb_control_msg(
+ hwarc->usb_dev, usb_sndctrlpipe(hwarc->usb_dev, 0),
+ WA_EXEC_RC_CMD, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, hwarc->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+ (void *) cmd, cmd_size, 100 /* FIXME: this is totally arbitrary */);
+}
+
+static
+int hwarc_reset(struct uwb_rc *uwb_rc)
+{
+ struct hwarc *hwarc = uwb_rc->priv;
+ return usb_reset_device(hwarc->usb_dev);
+}
+
+/**
+ * Callback for the notification and event endpoint
+ *
+ * Check's that everything is fine and then passes the read data to
+ * the notification/event handling mechanism (neh).
+ */
+static
+void hwarc_neep_cb(struct urb *urb)
+{
+ struct hwarc *hwarc = urb->context;
+ struct usb_interface *usb_iface = hwarc->usb_iface;
+ struct device *dev = &usb_iface->dev;
+ int result;
+
+ switch (result = urb->status) {
+ case 0:
+ d_printf(3, dev, "NEEP: receive stat %d, %zu bytes\n",
+ urb->status, (size_t)urb->actual_length);
+ uwb_rc_neh_grok(hwarc->uwb_rc, urb->transfer_buffer,
+ urb->actual_length);
+ break;
+ case -ECONNRESET: /* Not an error, but a controlled situation; */
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ d_printf(2, dev, "NEEP: URB reset/noent %d\n", urb->status);
+ goto out;
+ case -ESHUTDOWN: /* going away! */
+ d_printf(2, dev, "NEEP: URB down %d\n", urb->status);
+ goto out;
+ default: /* On general errors, retry unless it gets ugly */
+ if (edc_inc(&hwarc->neep_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME))
+ goto error_exceeded;
+ dev_err(dev, "NEEP: URB error %d\n", urb->status);
+ }
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ d_printf(3, dev, "NEEP: submit %d\n", result);
+ if (result < 0) {
+ dev_err(dev, "NEEP: Can't resubmit URB (%d) resetting device\n",
+ result);
+ goto error;
+ }
+out:
+ return;
+
+error_exceeded:
+ dev_err(dev, "NEEP: URB max acceptable errors "
+ "exceeded, resetting device\n");
+error:
+ uwb_rc_neh_error(hwarc->uwb_rc, result);
+ uwb_rc_reset_all(hwarc->uwb_rc);
+ return;
+}
+
+static void hwarc_init(struct hwarc *hwarc)
+{
+ edc_init(&hwarc->neep_edc);
+}
+
+/**
+ * Initialize the notification/event endpoint stuff
+ *
+ * Note this is effectively a parallel thread; it knows that
+ * hwarc->uwb_rc always exists because the existence of a 'hwarc'
+ * means that there is a reverence on the hwarc->uwb_rc (see
+ * _probe()), and thus _neep_cb() can execute safely.
+ */
+static int hwarc_neep_init(struct uwb_rc *rc)
+{
+ struct hwarc *hwarc = rc->priv;
+ struct usb_interface *iface = hwarc->usb_iface;
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+ struct device *dev = &iface->dev;
+ int result;
+ struct usb_endpoint_descriptor *epd;
+
+ epd = &iface->cur_altsetting->endpoint[0].desc;
+ hwarc->rd_buffer = (void *) __get_free_page(GFP_KERNEL);
+ if (hwarc->rd_buffer == NULL) {
+ dev_err(dev, "Unable to allocate notification's read buffer\n");
+ goto error_rd_buffer;
+ }
+ hwarc->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (hwarc->neep_urb == NULL) {
+ dev_err(dev, "Unable to allocate notification URB\n");
+ goto error_urb_alloc;
+ }
+ usb_fill_int_urb(hwarc->neep_urb, usb_dev,
+ usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
+ hwarc->rd_buffer, PAGE_SIZE,
+ hwarc_neep_cb, hwarc, epd->bInterval);
+ result = usb_submit_urb(hwarc->neep_urb, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "Cannot submit notification URB: %d\n", result);
+ goto error_neep_submit;
+ }
+ return 0;
+
+error_neep_submit:
+ usb_free_urb(hwarc->neep_urb);
+error_urb_alloc:
+ free_page((unsigned long)hwarc->rd_buffer);
+error_rd_buffer:
+ return -ENOMEM;
+}
+
+
+/** Clean up all the notification endpoint resources */
+static void hwarc_neep_release(struct uwb_rc *rc)
+{
+ struct hwarc *hwarc = rc->priv;
+
+ usb_kill_urb(hwarc->neep_urb);
+ usb_free_urb(hwarc->neep_urb);
+ free_page((unsigned long)hwarc->rd_buffer);
+}
+
+/**
+ * Get the version from class-specific descriptor
+ *
+ * NOTE: this descriptor comes with the big bundled configuration
+ * descriptor that includes the interfaces' and endpoints', so
+ * we just look for it in the cached copy kept by the USB stack.
+ *
+ * NOTE2: We convert LE fields to CPU order.
+ */
+static int hwarc_get_version(struct uwb_rc *rc)
+{
+ int result;
+
+ struct hwarc *hwarc = rc->priv;
+ struct uwb_rc_control_intf_class_desc *descr;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct usb_device *usb_dev = hwarc->usb_dev;
+ char *itr;
+ struct usb_descriptor_header *hdr;
+ size_t itr_size, actconfig_idx;
+ u16 version;
+
+ actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
+ sizeof(usb_dev->config[0]);
+ itr = usb_dev->rawdescriptors[actconfig_idx];
+ itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
+ while (itr_size >= sizeof(*hdr)) {
+ hdr = (struct usb_descriptor_header *) itr;
+ d_printf(3, dev, "Extra device descriptor: "
+ "type %02x/%u bytes @ %zu (%zu left)\n",
+ hdr->bDescriptorType, hdr->bLength,
+ (itr - usb_dev->rawdescriptors[actconfig_idx]),
+ itr_size);
+ if (hdr->bDescriptorType == USB_DT_CS_RADIO_CONTROL)
+ goto found;
+ itr += hdr->bLength;
+ itr_size -= hdr->bLength;
+ }
+ dev_err(dev, "cannot find Radio Control Interface Class descriptor\n");
+ return -ENODEV;
+
+found:
+ result = -EINVAL;
+ if (hdr->bLength > itr_size) { /* is it available? */
+ dev_err(dev, "incomplete Radio Control Interface Class "
+ "descriptor (%zu bytes left, %u needed)\n",
+ itr_size, hdr->bLength);
+ goto error;
+ }
+ if (hdr->bLength < sizeof(*descr)) {
+ dev_err(dev, "short Radio Control Interface Class "
+ "descriptor\n");
+ goto error;
+ }
+ descr = (struct uwb_rc_control_intf_class_desc *) hdr;
+ /* Make LE fields CPU order */
+ version = __le16_to_cpu(descr->bcdRCIVersion);
+ if (version != 0x0100) {
+ dev_err(dev, "Device reports protocol version 0x%04x. We "
+ "do not support that. \n", version);
+ result = -EINVAL;
+ goto error;
+ }
+ rc->version = version;
+ d_printf(3, dev, "Device supports WUSB protocol version 0x%04x \n",
+ rc->version);
+ result = 0;
+error:
+ return result;
+}
+
+/*
+ * By creating a 'uwb_rc', we have a reference on it -- that reference
+ * is the one we drop when we disconnect.
+ *
+ * No need to switch altsettings; according to WUSB1.0[8.6.1.1], there
+ * is only one altsetting allowed.
+ */
+static int hwarc_probe(struct usb_interface *iface,
+ const struct usb_device_id *id)
+{
+ int result;
+ struct uwb_rc *uwb_rc;
+ struct hwarc *hwarc;
+ struct device *dev = &iface->dev;
+
+ result = -ENOMEM;
+ uwb_rc = uwb_rc_alloc();
+ if (uwb_rc == NULL) {
+ dev_err(dev, "unable to allocate RC instance\n");
+ goto error_rc_alloc;
+ }
+ hwarc = kzalloc(sizeof(*hwarc), GFP_KERNEL);
+ if (hwarc == NULL) {
+ dev_err(dev, "unable to allocate HWA RC instance\n");
+ goto error_alloc;
+ }
+ hwarc_init(hwarc);
+ hwarc->usb_dev = usb_get_dev(interface_to_usbdev(iface));
+ hwarc->usb_iface = usb_get_intf(iface);
+ hwarc->uwb_rc = uwb_rc;
+
+ uwb_rc->owner = THIS_MODULE;
+ uwb_rc->start = hwarc_neep_init;
+ uwb_rc->stop = hwarc_neep_release;
+ uwb_rc->cmd = hwarc_cmd;
+ uwb_rc->reset = hwarc_reset;
+ if (id->driver_info & WUSB_QUIRK_WHCI_CMD_EVT) {
+ uwb_rc->filter_cmd = NULL;
+ uwb_rc->filter_event = NULL;
+ } else {
+ uwb_rc->filter_cmd = hwarc_filter_cmd;
+ uwb_rc->filter_event = hwarc_filter_event;
+ }
+
+ result = uwb_rc_add(uwb_rc, dev, hwarc);
+ if (result < 0)
+ goto error_rc_add;
+ result = hwarc_get_version(uwb_rc);
+ if (result < 0) {
+ dev_err(dev, "cannot retrieve version of RC \n");
+ goto error_get_version;
+ }
+ usb_set_intfdata(iface, hwarc);
+ return 0;
+
+error_get_version:
+ uwb_rc_rm(uwb_rc);
+error_rc_add:
+ usb_put_intf(iface);
+ usb_put_dev(hwarc->usb_dev);
+error_alloc:
+ uwb_rc_put(uwb_rc);
+error_rc_alloc:
+ return result;
+}
+
+static void hwarc_disconnect(struct usb_interface *iface)
+{
+ struct hwarc *hwarc = usb_get_intfdata(iface);
+ struct uwb_rc *uwb_rc = hwarc->uwb_rc;
+
+ usb_set_intfdata(hwarc->usb_iface, NULL);
+ uwb_rc_rm(uwb_rc);
+ usb_put_intf(hwarc->usb_iface);
+ usb_put_dev(hwarc->usb_dev);
+ d_printf(1, &hwarc->usb_iface->dev, "freed hwarc %p\n", hwarc);
+ kfree(hwarc);
+ uwb_rc_put(uwb_rc); /* when creating the device, refcount = 1 */
+}
+
+/** USB device ID's that we handle */
+static struct usb_device_id hwarc_id_table[] = {
+ /* D-Link DUB-1210 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3d02, 0xe0, 0x01, 0x02),
+ .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+ /* Intel i1480 (using firmware 1.3PA2-20070828) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x8086, 0x0c3b, 0xe0, 0x01, 0x02),
+ .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+ /* Generic match for the Radio Control interface */
+ { USB_INTERFACE_INFO(0xe0, 0x01, 0x02), },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, hwarc_id_table);
+
+static struct usb_driver hwarc_driver = {
+ .name = "hwa-rc",
+ .probe = hwarc_probe,
+ .disconnect = hwarc_disconnect,
+ .id_table = hwarc_id_table,
+};
+
+static int __init hwarc_driver_init(void)
+{
+ int result;
+ result = usb_register(&hwarc_driver);
+ if (result < 0)
+ printk(KERN_ERR "HWA-RC: Cannot register USB driver: %d\n",
+ result);
+ return result;
+
+}
+module_init(hwarc_driver_init);
+
+static void __exit hwarc_driver_exit(void)
+{
+ usb_deregister(&hwarc_driver);
+}
+module_exit(hwarc_driver_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Host Wireless Adapter Radio Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/i1480/Makefile b/drivers/uwb/i1480/Makefile
new file mode 100644
index 00000000000..212bbc7d4c3
--- /dev/null
+++ b/drivers/uwb/i1480/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o
+obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp/
diff --git a/drivers/uwb/i1480/dfu/Makefile b/drivers/uwb/i1480/dfu/Makefile
new file mode 100644
index 00000000000..bd1b9f25424
--- /dev/null
+++ b/drivers/uwb/i1480/dfu/Makefile
@@ -0,0 +1,9 @@
+obj-$(CONFIG_UWB_I1480U) += i1480-dfu-usb.o
+
+i1480-dfu-usb-objs := \
+ dfu.o \
+ mac.o \
+ phy.o \
+ usb.o
+
+
diff --git a/drivers/uwb/i1480/dfu/dfu.c b/drivers/uwb/i1480/dfu/dfu.c
new file mode 100644
index 00000000000..9097b3b3038
--- /dev/null
+++ b/drivers/uwb/i1480/dfu/dfu.c
@@ -0,0 +1,217 @@
+/*
+ * Intel Wireless UWB Link 1480
+ * Main driver
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * Common code for firmware upload used by the USB and PCI version;
+ * i1480_fw_upload() takes a device descriptor and uses the function
+ * pointers it provides to upload firmware and prepare the PHY.
+ *
+ * As well, provides common functions used by the rest of the code.
+ */
+#include "i1480-dfu.h"
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/uwb.h>
+#include <linux/random.h>
+
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+/**
+ * i1480_rceb_check - Check RCEB for expected field values
+ * @i1480: pointer to device for which RCEB is being checked
+ * @rceb: RCEB being checked
+ * @cmd: which command the RCEB is related to
+ * @context: expected context
+ * @expected_type: expected event type
+ * @expected_event: expected event
+ *
+ * If @cmd is NULL, do not print error messages, but still return an error
+ * code.
+ *
+ * Return 0 if @rceb matches the expected values, -EINVAL otherwise.
+ */
+int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb,
+ const char *cmd, u8 context, u8 expected_type,
+ unsigned expected_event)
+{
+ int result = 0;
+ struct device *dev = i1480->dev;
+ if (rceb->bEventContext != context) {
+ if (cmd)
+ dev_err(dev, "%s: unexpected context id 0x%02x "
+ "(expected 0x%02x)\n", cmd,
+ rceb->bEventContext, context);
+ result = -EINVAL;
+ }
+ if (rceb->bEventType != expected_type) {
+ if (cmd)
+ dev_err(dev, "%s: unexpected event type 0x%02x "
+ "(expected 0x%02x)\n", cmd,
+ rceb->bEventType, expected_type);
+ result = -EINVAL;
+ }
+ if (le16_to_cpu(rceb->wEvent) != expected_event) {
+ if (cmd)
+ dev_err(dev, "%s: unexpected event 0x%04x "
+ "(expected 0x%04x)\n", cmd,
+ le16_to_cpu(rceb->wEvent), expected_event);
+ result = -EINVAL;
+ }
+ return result;
+}
+EXPORT_SYMBOL_GPL(i1480_rceb_check);
+
+
+/**
+ * Execute a Radio Control Command
+ *
+ * Command data has to be in i1480->cmd_buf.
+ *
+ * @returns size of the reply data filled in i1480->evt_buf or < 0 errno
+ * code on error.
+ */
+ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size,
+ size_t reply_size)
+{
+ ssize_t result;
+ struct uwb_rceb *reply = i1480->evt_buf;
+ struct uwb_rccb *cmd = i1480->cmd_buf;
+ u16 expected_event = reply->wEvent;
+ u8 expected_type = reply->bEventType;
+ u8 context;
+
+ d_fnstart(3, i1480->dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size);
+ init_completion(&i1480->evt_complete);
+ i1480->evt_result = -EINPROGRESS;
+ do {
+ get_random_bytes(&context, 1);
+ } while (context == 0x00 || context == 0xff);
+ cmd->bCommandContext = context;
+ result = i1480->cmd(i1480, cmd_name, cmd_size);
+ if (result < 0)
+ goto error;
+ /* wait for the callback to report a event was received */
+ result = wait_for_completion_interruptible_timeout(
+ &i1480->evt_complete, HZ);
+ if (result == 0) {
+ result = -ETIMEDOUT;
+ goto error;
+ }
+ if (result < 0)
+ goto error;
+ result = i1480->evt_result;
+ if (result < 0) {
+ dev_err(i1480->dev, "%s: command reply reception failed: %zd\n",
+ cmd_name, result);
+ goto error;
+ }
+ /*
+ * Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a
+ * spurious notification after firmware is downloaded. So check whether
+ * the receibed RCEB is such notification before assuming that the
+ * command has failed.
+ */
+ if (i1480_rceb_check(i1480, i1480->evt_buf, NULL,
+ 0, 0xfd, 0x0022) == 0) {
+ /* Now wait for the actual RCEB for this command. */
+ result = i1480->wait_init_done(i1480);
+ if (result < 0)
+ goto error;
+ result = i1480->evt_result;
+ }
+ if (result != reply_size) {
+ dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n",
+ cmd_name, result, reply_size);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Verify we got the right event in response */
+ result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context,
+ expected_type, expected_event);
+error:
+ d_fnend(3, i1480->dev, "(%p, %s, %zu) = %zd\n",
+ i1480, cmd_name, cmd_size, result);
+ return result;
+}
+EXPORT_SYMBOL_GPL(i1480_cmd);
+
+
+static
+int i1480_print_state(struct i1480 *i1480)
+{
+ int result;
+ u32 *buf = (u32 *) i1480->cmd_buf;
+
+ result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf));
+ if (result < 0) {
+ dev_err(i1480->dev, "cannot read U & L states: %d\n", result);
+ goto error;
+ }
+ dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]);
+error:
+ return result;
+}
+
+
+/*
+ * PCI probe, firmware uploader
+ *
+ * _mac_fw_upload() will call rc_setup(), which needs an rc_release().
+ */
+int i1480_fw_upload(struct i1480 *i1480)
+{
+ int result;
+
+ result = i1480_pre_fw_upload(i1480); /* PHY pre fw */
+ if (result < 0 && result != -ENOENT) {
+ i1480_print_state(i1480);
+ goto error;
+ }
+ result = i1480_mac_fw_upload(i1480); /* MAC fw */
+ if (result < 0) {
+ if (result == -ENOENT)
+ dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n",
+ i1480->mac_fw_name);
+ else
+ i1480_print_state(i1480);
+ goto error;
+ }
+ result = i1480_phy_fw_upload(i1480); /* PHY fw */
+ if (result < 0 && result != -ENOENT) {
+ i1480_print_state(i1480);
+ goto error_rc_release;
+ }
+ /*
+ * FIXME: find some reliable way to check whether firmware is running
+ * properly. Maybe use some standard request that has no side effects?
+ */
+ dev_info(i1480->dev, "firmware uploaded successfully\n");
+error_rc_release:
+ if (i1480->rc_release)
+ i1480->rc_release(i1480);
+ result = 0;
+error:
+ return result;
+}
+EXPORT_SYMBOL_GPL(i1480_fw_upload);
diff --git a/drivers/uwb/i1480/dfu/i1480-dfu.h b/drivers/uwb/i1480/dfu/i1480-dfu.h
new file mode 100644
index 00000000000..46f45e800f3
--- /dev/null
+++ b/drivers/uwb/i1480/dfu/i1480-dfu.h
@@ -0,0 +1,260 @@
+/*
+ * i1480 Device Firmware Upload
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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 driver is the firmware uploader for the Intel Wireless UWB
+ * Link 1480 device (both in the USB and PCI incarnations).
+ *
+ * The process is quite simple: we stop the device, write the firmware
+ * to its memory and then restart it. Wait for the device to let us
+ * know it is done booting firmware. Ready.
+ *
+ * We might have to upload before or after a phy firmware (which might
+ * be done in two methods, using a normal firmware image or through
+ * the MPI port).
+ *
+ * Because USB and PCI use common methods, we just make ops out of the
+ * common operations (read, write, wait_init_done and cmd) and
+ * implement them in usb.c and pci.c.
+ *
+ * The flow is (some parts omitted):
+ *
+ * i1480_{usb,pci}_probe() On enumerate/discovery
+ * i1480_fw_upload()
+ * i1480_pre_fw_upload()
+ * __mac_fw_upload()
+ * fw_hdrs_load()
+ * mac_fw_hdrs_push()
+ * i1480->write() [i1480_{usb,pci}_write()]
+ * i1480_fw_cmp()
+ * i1480->read() [i1480_{usb,pci}_read()]
+ * i1480_mac_fw_upload()
+ * __mac_fw_upload()
+ * i1480->setup(()
+ * i1480->wait_init_done()
+ * i1480_cmd_reset()
+ * i1480->cmd() [i1480_{usb,pci}_cmd()]
+ * ...
+ * i1480_phy_fw_upload()
+ * request_firmware()
+ * i1480_mpi_write()
+ * i1480->cmd() [i1480_{usb,pci}_cmd()]
+ *
+ * Once the probe function enumerates the device and uploads the
+ * firmware, we just exit with -ENODEV, as we don't really want to
+ * attach to the device.
+ */
+#ifndef __i1480_DFU_H__
+#define __i1480_DFU_H__
+
+#include <linux/uwb/spec.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+
+#define i1480_FW_UPLOAD_MODE_MASK (cpu_to_le32(0x00000018))
+
+#if i1480_FW > 0x00000302
+#define i1480_RCEB_EXTENDED
+#endif
+
+struct uwb_rccb;
+struct uwb_rceb;
+
+/*
+ * Common firmware upload handlers
+ *
+ * Normally you embed this struct in another one specific to your hw.
+ *
+ * @write Write to device's memory from buffer.
+ * @read Read from device's memory to i1480->evt_buf.
+ * @setup Setup device after basic firmware is uploaded
+ * @wait_init_done
+ * Wait for the device to send a notification saying init
+ * is done.
+ * @cmd FOP for issuing the command to the hardware. The
+ * command data is contained in i1480->cmd_buf and the size
+ * is supplied as an argument. The command replied is put
+ * in i1480->evt_buf and the size in i1480->evt_result (or if
+ * an error, a < 0 errno code).
+ *
+ * @cmd_buf Memory buffer used to send commands to the device.
+ * Allocated by the upper layers i1480_fw_upload().
+ * Size has to be @buf_size.
+ * @evt_buf Memory buffer used to place the async notifications
+ * received by the hw. Allocated by the upper layers
+ * i1480_fw_upload().
+ * Size has to be @buf_size.
+ * @cmd_complete
+ * Low level driver uses this to notify code waiting afor
+ * an event that the event has arrived and data is in
+ * i1480->evt_buf (and size/result in i1480->evt_result).
+ * @hw_rev
+ * Use this value to activate dfu code to support new revisions
+ * of hardware. i1480_init() sets this to a default value.
+ * It should be updated by the USB and PCI code.
+ */
+struct i1480 {
+ struct device *dev;
+
+ int (*write)(struct i1480 *, u32 addr, const void *, size_t);
+ int (*read)(struct i1480 *, u32 addr, size_t);
+ int (*rc_setup)(struct i1480 *);
+ void (*rc_release)(struct i1480 *);
+ int (*wait_init_done)(struct i1480 *);
+ int (*cmd)(struct i1480 *, const char *cmd_name, size_t cmd_size);
+ const char *pre_fw_name;
+ const char *mac_fw_name;
+ const char *mac_fw_name_deprecate; /* FIXME: Will go away */
+ const char *phy_fw_name;
+ u8 hw_rev;
+
+ size_t buf_size; /* size of both evt_buf and cmd_buf */
+ void *evt_buf, *cmd_buf;
+ ssize_t evt_result;
+ struct completion evt_complete;
+};
+
+static inline
+void i1480_init(struct i1480 *i1480)
+{
+ i1480->hw_rev = 1;
+ init_completion(&i1480->evt_complete);
+}
+
+extern int i1480_fw_upload(struct i1480 *);
+extern int i1480_pre_fw_upload(struct i1480 *);
+extern int i1480_mac_fw_upload(struct i1480 *);
+extern int i1480_phy_fw_upload(struct i1480 *);
+extern ssize_t i1480_cmd(struct i1480 *, const char *, size_t, size_t);
+extern int i1480_rceb_check(const struct i1480 *,
+ const struct uwb_rceb *, const char *, u8,
+ u8, unsigned);
+
+enum {
+ /* Vendor specific command type */
+ i1480_CET_VS1 = 0xfd,
+ /* i1480 commands */
+ i1480_CMD_SET_IP_MAS = 0x000e,
+ i1480_CMD_GET_MAC_PHY_INFO = 0x0003,
+ i1480_CMD_MPI_WRITE = 0x000f,
+ i1480_CMD_MPI_READ = 0x0010,
+ /* i1480 events */
+#if i1480_FW > 0x00000302
+ i1480_EVT_CONFIRM = 0x0002,
+ i1480_EVT_RM_INIT_DONE = 0x0101,
+ i1480_EVT_DEV_ADD = 0x0103,
+ i1480_EVT_DEV_RM = 0x0104,
+ i1480_EVT_DEV_ID_CHANGE = 0x0105,
+ i1480_EVT_GET_MAC_PHY_INFO = i1480_CMD_GET_MAC_PHY_INFO,
+#else
+ i1480_EVT_CONFIRM = 0x0002,
+ i1480_EVT_RM_INIT_DONE = 0x0101,
+ i1480_EVT_DEV_ADD = 0x0103,
+ i1480_EVT_DEV_RM = 0x0104,
+ i1480_EVT_DEV_ID_CHANGE = 0x0105,
+ i1480_EVT_GET_MAC_PHY_INFO = i1480_EVT_CONFIRM,
+#endif
+};
+
+
+struct i1480_evt_confirm {
+ struct uwb_rceb rceb;
+#ifdef i1480_RCEB_EXTENDED
+ __le16 wParamLength;
+#endif
+ u8 bResultCode;
+} __attribute__((packed));
+
+
+struct i1480_rceb {
+ struct uwb_rceb rceb;
+#ifdef i1480_RCEB_EXTENDED
+ __le16 wParamLength;
+#endif
+} __attribute__((packed));
+
+
+/**
+ * Get MAC & PHY Information confirm event structure
+ *
+ * Confirm event returned by the command.
+ */
+struct i1480_evt_confirm_GMPI {
+#if i1480_FW > 0x00000302
+ struct uwb_rceb rceb;
+ __le16 wParamLength;
+ __le16 status;
+ u8 mac_addr[6]; /* EUI-64 bit IEEE address [still 8 bytes?] */
+ u8 dev_addr[2];
+ __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */
+ u8 hw_rev;
+ u8 phy_vendor;
+ u8 phy_rev; /* major v = >> 8; minor = v & 0xff */
+ __le16 mac_caps;
+ u8 phy_caps[3];
+ u8 key_stores;
+ __le16 mcast_addr_stores;
+ u8 sec_mode_supported;
+#else
+ struct uwb_rceb rceb;
+ u8 status;
+ u8 mac_addr[8]; /* EUI-64 bit IEEE address [still 8 bytes?] */
+ u8 dev_addr[2];
+ __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */
+ __le16 phy_fw_rev; /* major v = >> 8; minor = v & 0xff */
+ __le16 mac_caps;
+ u8 phy_caps;
+ u8 key_stores;
+ __le16 mcast_addr_stores;
+ u8 sec_mode_supported;
+#endif
+} __attribute__((packed));
+
+
+struct i1480_cmd_mpi_write {
+ struct uwb_rccb rccb;
+ __le16 size;
+ u8 data[];
+};
+
+
+struct i1480_cmd_mpi_read {
+ struct uwb_rccb rccb;
+ __le16 size;
+ struct {
+ u8 page, offset;
+ } __attribute__((packed)) data[];
+} __attribute__((packed));
+
+
+struct i1480_evt_mpi_read {
+ struct uwb_rceb rceb;
+#ifdef i1480_RCEB_EXTENDED
+ __le16 wParamLength;
+#endif
+ u8 bResultCode;
+ __le16 size;
+ struct {
+ u8 page, offset, value;
+ } __attribute__((packed)) data[];
+} __attribute__((packed));
+
+
+#endif /* #ifndef __i1480_DFU_H__ */
diff --git a/drivers/uwb/i1480/dfu/mac.c b/drivers/uwb/i1480/dfu/mac.c
new file mode 100644
index 00000000000..2e4d8f07c16
--- /dev/null
+++ b/drivers/uwb/i1480/dfu/mac.c
@@ -0,0 +1,527 @@
+/*
+ * Intel Wireless UWB Link 1480
+ * MAC Firmware upload implementation
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * Implementation of the code for parsing the firmware file (extract
+ * the headers and binary code chunks) in the fw_*() functions. The
+ * code to upload pre and mac firmwares is the same, so it uses a
+ * common entry point in __mac_fw_upload(), which uses the i1480
+ * function pointers to push the firmware to the device.
+ */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/uwb.h>
+#include "i1480-dfu.h"
+
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+/*
+ * Descriptor for a continuous segment of MAC fw data
+ */
+struct fw_hdr {
+ unsigned long address;
+ size_t length;
+ const u32 *bin;
+ struct fw_hdr *next;
+};
+
+
+/* Free a chain of firmware headers */
+static
+void fw_hdrs_free(struct fw_hdr *hdr)
+{
+ struct fw_hdr *next;
+
+ while (hdr) {
+ next = hdr->next;
+ kfree(hdr);
+ hdr = next;
+ }
+}
+
+
+/* Fill a firmware header descriptor from a memory buffer */
+static
+int fw_hdr_load(struct i1480 *i1480, struct fw_hdr *hdr, unsigned hdr_cnt,
+ const char *_data, const u32 *data_itr, const u32 *data_top)
+{
+ size_t hdr_offset = (const char *) data_itr - _data;
+ size_t remaining_size = (void *) data_top - (void *) data_itr;
+ if (data_itr + 2 > data_top) {
+ dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in header at "
+ "offset %zu, limit %zu\n",
+ hdr_cnt, hdr_offset,
+ (const char *) data_itr + 2 - _data,
+ (const char *) data_top - _data);
+ return -EINVAL;
+ }
+ hdr->next = NULL;
+ hdr->address = le32_to_cpu(*data_itr++);
+ hdr->length = le32_to_cpu(*data_itr++);
+ hdr->bin = data_itr;
+ if (hdr->length > remaining_size) {
+ dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in data; "
+ "chunk too long (%zu bytes), only %zu left\n",
+ hdr_cnt, hdr_offset, hdr->length, remaining_size);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+/**
+ * Get a buffer where the firmware is supposed to be and create a
+ * chain of headers linking them together.
+ *
+ * @phdr: where to place the pointer to the first header (headers link
+ * to the next via the @hdr->next ptr); need to free the whole
+ * chain when done.
+ *
+ * @_data: Pointer to the data buffer.
+ *
+ * @_data_size: Size of the data buffer (bytes); data size has to be a
+ * multiple of 4. Function will fail if not.
+ *
+ * Goes over the whole binary blob; reads the first chunk and creates
+ * a fw hdr from it (which points to where the data is in @_data and
+ * the length of the chunk); then goes on to the next chunk until
+ * done. Each header is linked to the next.
+ */
+static
+int fw_hdrs_load(struct i1480 *i1480, struct fw_hdr **phdr,
+ const char *_data, size_t data_size)
+{
+ int result;
+ unsigned hdr_cnt = 0;
+ u32 *data = (u32 *) _data, *data_itr, *data_top;
+ struct fw_hdr *hdr, **prev_hdr = phdr;
+
+ result = -EINVAL;
+ /* Check size is ok and pointer is aligned */
+ if (data_size % sizeof(u32) != 0)
+ goto error;
+ if ((unsigned long) _data % sizeof(u16) != 0)
+ goto error;
+ *phdr = NULL;
+ data_itr = data;
+ data_top = (u32 *) (_data + data_size);
+ while (data_itr < data_top) {
+ result = -ENOMEM;
+ hdr = kmalloc(sizeof(*hdr), GFP_KERNEL);
+ if (hdr == NULL) {
+ dev_err(i1480->dev, "Cannot allocate fw header "
+ "for chunk #%u\n", hdr_cnt);
+ goto error_alloc;
+ }
+ result = fw_hdr_load(i1480, hdr, hdr_cnt,
+ _data, data_itr, data_top);
+ if (result < 0)
+ goto error_load;
+ data_itr += 2 + hdr->length;
+ *prev_hdr = hdr;
+ prev_hdr = &hdr->next;
+ hdr_cnt++;
+ };
+ *prev_hdr = NULL;
+ return 0;
+
+error_load:
+ kfree(hdr);
+error_alloc:
+ fw_hdrs_free(*phdr);
+error:
+ return result;
+}
+
+
+/**
+ * Compares a chunk of fw with one in the devices's memory
+ *
+ * @i1480: Device instance
+ * @hdr: Pointer to the firmware chunk
+ * @returns: 0 if equal, < 0 errno on error. If > 0, it is the offset
+ * where the difference was found (plus one).
+ *
+ * Kind of dirty and simplistic, but does the trick in both the PCI
+ * and USB version. We do a quick[er] memcmp(), and if it fails, we do
+ * a byte-by-byte to find the offset.
+ */
+static
+ssize_t i1480_fw_cmp(struct i1480 *i1480, struct fw_hdr *hdr)
+{
+ ssize_t result = 0;
+ u32 src_itr = 0, cnt;
+ size_t size = hdr->length*sizeof(hdr->bin[0]);
+ size_t chunk_size;
+ u8 *bin = (u8 *) hdr->bin;
+
+ while (size > 0) {
+ chunk_size = size < i1480->buf_size ? size : i1480->buf_size;
+ result = i1480->read(i1480, hdr->address + src_itr, chunk_size);
+ if (result < 0) {
+ dev_err(i1480->dev, "error reading for verification: "
+ "%zd\n", result);
+ goto error;
+ }
+ if (memcmp(i1480->cmd_buf, bin + src_itr, result)) {
+ u8 *buf = i1480->cmd_buf;
+ d_printf(2, i1480->dev,
+ "original data @ %p + %u, %zu bytes\n",
+ bin, src_itr, result);
+ d_dump(4, i1480->dev, bin + src_itr, result);
+ for (cnt = 0; cnt < result; cnt++)
+ if (bin[src_itr + cnt] != buf[cnt]) {
+ dev_err(i1480->dev, "byte failed at "
+ "src_itr %u cnt %u [0x%02x "
+ "vs 0x%02x]\n", src_itr, cnt,
+ bin[src_itr + cnt], buf[cnt]);
+ result = src_itr + cnt + 1;
+ goto cmp_failed;
+ }
+ }
+ src_itr += result;
+ size -= result;
+ }
+ result = 0;
+error:
+cmp_failed:
+ return result;
+}
+
+
+/**
+ * Writes firmware headers to the device.
+ *
+ * @prd: PRD instance
+ * @hdr: Processed firmware
+ * @returns: 0 if ok, < 0 errno on error.
+ */
+static
+int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr,
+ const char *fw_name, const char *fw_tag)
+{
+ struct device *dev = i1480->dev;
+ ssize_t result = 0;
+ struct fw_hdr *hdr_itr;
+ int verif_retry_count;
+
+ d_fnstart(3, dev, "(%p, %p)\n", i1480, hdr);
+ /* Now, header by header, push them to the hw */
+ for (hdr_itr = hdr; hdr_itr != NULL; hdr_itr = hdr_itr->next) {
+ verif_retry_count = 0;
+retry:
+ dev_dbg(dev, "fw chunk (%zu @ 0x%08lx)\n",
+ hdr_itr->length * sizeof(hdr_itr->bin[0]),
+ hdr_itr->address);
+ result = i1480->write(i1480, hdr_itr->address, hdr_itr->bin,
+ hdr_itr->length*sizeof(hdr_itr->bin[0]));
+ if (result < 0) {
+ dev_err(dev, "%s fw '%s': write failed (%zuB @ 0x%lx):"
+ " %zd\n", fw_tag, fw_name,
+ hdr_itr->length * sizeof(hdr_itr->bin[0]),
+ hdr_itr->address, result);
+ break;
+ }
+ result = i1480_fw_cmp(i1480, hdr_itr);
+ if (result < 0) {
+ dev_err(dev, "%s fw '%s': verification read "
+ "failed (%zuB @ 0x%lx): %zd\n",
+ fw_tag, fw_name,
+ hdr_itr->length * sizeof(hdr_itr->bin[0]),
+ hdr_itr->address, result);
+ break;
+ }
+ if (result > 0) { /* Offset where it failed + 1 */
+ result--;
+ dev_err(dev, "%s fw '%s': WARNING: verification "
+ "failed at 0x%lx: retrying\n",
+ fw_tag, fw_name, hdr_itr->address + result);
+ if (++verif_retry_count < 3)
+ goto retry; /* write this block again! */
+ dev_err(dev, "%s fw '%s': verification failed at 0x%lx: "
+ "tried %d times\n", fw_tag, fw_name,
+ hdr_itr->address + result, verif_retry_count);
+ result = -EINVAL;
+ break;
+ }
+ }
+ d_fnend(3, dev, "(%zd)\n", result);
+ return result;
+}
+
+
+/** Puts the device in firmware upload mode.*/
+static
+int mac_fw_upload_enable(struct i1480 *i1480)
+{
+ int result;
+ u32 reg = 0x800000c0;
+ u32 *buffer = (u32 *)i1480->cmd_buf;
+
+ if (i1480->hw_rev > 1)
+ reg = 0x8000d0d4;
+ result = i1480->read(i1480, reg, sizeof(u32));
+ if (result < 0)
+ goto error_cmd;
+ *buffer &= ~i1480_FW_UPLOAD_MODE_MASK;
+ result = i1480->write(i1480, reg, buffer, sizeof(u32));
+ if (result < 0)
+ goto error_cmd;
+ return 0;
+error_cmd:
+ dev_err(i1480->dev, "can't enable fw upload mode: %d\n", result);
+ return result;
+}
+
+
+/** Gets the device out of firmware upload mode. */
+static
+int mac_fw_upload_disable(struct i1480 *i1480)
+{
+ int result;
+ u32 reg = 0x800000c0;
+ u32 *buffer = (u32 *)i1480->cmd_buf;
+
+ if (i1480->hw_rev > 1)
+ reg = 0x8000d0d4;
+ result = i1480->read(i1480, reg, sizeof(u32));
+ if (result < 0)
+ goto error_cmd;
+ *buffer |= i1480_FW_UPLOAD_MODE_MASK;
+ result = i1480->write(i1480, reg, buffer, sizeof(u32));
+ if (result < 0)
+ goto error_cmd;
+ return 0;
+error_cmd:
+ dev_err(i1480->dev, "can't disable fw upload mode: %d\n", result);
+ return result;
+}
+
+
+
+/**
+ * Generic function for uploading a MAC firmware.
+ *
+ * @i1480: Device instance
+ * @fw_name: Name of firmware file to upload.
+ * @fw_tag: Name of the firmware type (for messages)
+ * [eg: MAC, PRE]
+ * @do_wait: Wait for device to emit initialization done message (0
+ * for PRE fws, 1 for MAC fws).
+ * @returns: 0 if ok, < 0 errno on error.
+ */
+static
+int __mac_fw_upload(struct i1480 *i1480, const char *fw_name,
+ const char *fw_tag)
+{
+ int result;
+ const struct firmware *fw;
+ struct fw_hdr *fw_hdrs;
+
+ d_fnstart(3, i1480->dev, "(%p, %s, %s)\n", i1480, fw_name, fw_tag);
+ result = request_firmware(&fw, fw_name, i1480->dev);
+ if (result < 0) /* Up to caller to complain on -ENOENT */
+ goto out;
+ d_printf(3, i1480->dev, "%s fw '%s': uploading\n", fw_tag, fw_name);
+ result = fw_hdrs_load(i1480, &fw_hdrs, fw->data, fw->size);
+ if (result < 0) {
+ dev_err(i1480->dev, "%s fw '%s': failed to parse firmware "
+ "file: %d\n", fw_tag, fw_name, result);
+ goto out_release;
+ }
+ result = mac_fw_upload_enable(i1480);
+ if (result < 0)
+ goto out_hdrs_release;
+ result = mac_fw_hdrs_push(i1480, fw_hdrs, fw_name, fw_tag);
+ mac_fw_upload_disable(i1480);
+out_hdrs_release:
+ if (result >= 0)
+ dev_info(i1480->dev, "%s fw '%s': uploaded\n", fw_tag, fw_name);
+ else
+ dev_err(i1480->dev, "%s fw '%s': failed to upload (%d), "
+ "power cycle device\n", fw_tag, fw_name, result);
+ fw_hdrs_free(fw_hdrs);
+out_release:
+ release_firmware(fw);
+out:
+ d_fnend(3, i1480->dev, "(%p, %s, %s) = %d\n", i1480, fw_name, fw_tag,
+ result);
+ return result;
+}
+
+
+/**
+ * Upload a pre-PHY firmware
+ *
+ */
+int i1480_pre_fw_upload(struct i1480 *i1480)
+{
+ int result;
+ result = __mac_fw_upload(i1480, i1480->pre_fw_name, "PRE");
+ if (result == 0)
+ msleep(400);
+ return result;
+}
+
+
+/**
+ * Reset a the MAC and PHY
+ *
+ * @i1480: Device's instance
+ * @returns: 0 if ok, < 0 errno code on error
+ *
+ * We put the command on kmalloc'ed memory as some arches cannot do
+ * USB from the stack. The reply event is copied from an stage buffer,
+ * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
+ *
+ * We issue the reset to make sure the UWB controller reinits the PHY;
+ * this way we can now if the PHY init went ok.
+ */
+static
+int i1480_cmd_reset(struct i1480 *i1480)
+{
+ int result;
+ struct uwb_rccb *cmd = (void *) i1480->cmd_buf;
+ struct i1480_evt_reset {
+ struct uwb_rceb rceb;
+ u8 bResultCode;
+ } __attribute__((packed)) *reply = (void *) i1480->evt_buf;
+
+ result = -ENOMEM;
+ cmd->bCommandType = UWB_RC_CET_GENERAL;
+ cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
+ reply->rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply->rceb.wEvent = UWB_RC_CMD_RESET;
+ result = i1480_cmd(i1480, "RESET", sizeof(*cmd), sizeof(*reply));
+ if (result < 0)
+ goto out;
+ if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(i1480->dev, "RESET: command execution failed: %u\n",
+ reply->bResultCode);
+ result = -EIO;
+ }
+out:
+ return result;
+
+}
+
+
+/* Wait for the MAC FW to start running */
+static
+int i1480_fw_is_running_q(struct i1480 *i1480)
+{
+ int cnt = 0;
+ int result;
+ u32 *val = (u32 *) i1480->cmd_buf;
+
+ d_fnstart(3, i1480->dev, "(i1480 %p)\n", i1480);
+ for (cnt = 0; cnt < 10; cnt++) {
+ msleep(100);
+ result = i1480->read(i1480, 0x80080000, 4);
+ if (result < 0) {
+ dev_err(i1480->dev, "Can't read 0x8008000: %d\n", result);
+ goto out;
+ }
+ if (*val == 0x55555555UL) /* fw running? cool */
+ goto out;
+ }
+ dev_err(i1480->dev, "Timed out waiting for fw to start\n");
+ result = -ETIMEDOUT;
+out:
+ d_fnend(3, i1480->dev, "(i1480 %p) = %d\n", i1480, result);
+ return result;
+
+}
+
+
+/**
+ * Upload MAC firmware, wait for it to start
+ *
+ * @i1480: Device instance
+ * @fw_name: Name of the file that contains the firmware
+ *
+ * This has to be called after the pre fw has been uploaded (if
+ * there is any).
+ */
+int i1480_mac_fw_upload(struct i1480 *i1480)
+{
+ int result = 0, deprecated_name = 0;
+ struct i1480_rceb *rcebe = (void *) i1480->evt_buf;
+
+ d_fnstart(3, i1480->dev, "(%p)\n", i1480);
+ result = __mac_fw_upload(i1480, i1480->mac_fw_name, "MAC");
+ if (result == -ENOENT) {
+ result = __mac_fw_upload(i1480, i1480->mac_fw_name_deprecate,
+ "MAC");
+ deprecated_name = 1;
+ }
+ if (result < 0)
+ return result;
+ if (deprecated_name == 1)
+ dev_warn(i1480->dev,
+ "WARNING: firmware file name %s is deprecated, "
+ "please rename to %s\n",
+ i1480->mac_fw_name_deprecate, i1480->mac_fw_name);
+ result = i1480_fw_is_running_q(i1480);
+ if (result < 0)
+ goto error_fw_not_running;
+ result = i1480->rc_setup ? i1480->rc_setup(i1480) : 0;
+ if (result < 0) {
+ dev_err(i1480->dev, "Cannot setup after MAC fw upload: %d\n",
+ result);
+ goto error_setup;
+ }
+ result = i1480->wait_init_done(i1480); /* wait init'on */
+ if (result < 0) {
+ dev_err(i1480->dev, "MAC fw '%s': Initialization timed out "
+ "(%d)\n", i1480->mac_fw_name, result);
+ goto error_init_timeout;
+ }
+ /* verify we got the right initialization done event */
+ if (i1480->evt_result != sizeof(*rcebe)) {
+ dev_err(i1480->dev, "MAC fw '%s': initialization event returns "
+ "wrong size (%zu bytes vs %zu needed)\n",
+ i1480->mac_fw_name, i1480->evt_result, sizeof(*rcebe));
+ dump_bytes(i1480->dev, rcebe, min(i1480->evt_result, (ssize_t)32));
+ goto error_size;
+ }
+ result = -EIO;
+ if (i1480_rceb_check(i1480, &rcebe->rceb, NULL, 0, i1480_CET_VS1,
+ i1480_EVT_RM_INIT_DONE) < 0) {
+ dev_err(i1480->dev, "wrong initialization event 0x%02x/%04x/%02x "
+ "received; expected 0x%02x/%04x/00\n",
+ rcebe->rceb.bEventType, le16_to_cpu(rcebe->rceb.wEvent),
+ rcebe->rceb.bEventContext, i1480_CET_VS1,
+ i1480_EVT_RM_INIT_DONE);
+ goto error_init_timeout;
+ }
+ result = i1480_cmd_reset(i1480);
+ if (result < 0)
+ dev_err(i1480->dev, "MAC fw '%s': MBOA reset failed (%d)\n",
+ i1480->mac_fw_name, result);
+error_fw_not_running:
+error_init_timeout:
+error_size:
+error_setup:
+ d_fnend(3, i1480->dev, "(i1480 %p) = %d\n", i1480, result);
+ return result;
+}
diff --git a/drivers/uwb/i1480/dfu/phy.c b/drivers/uwb/i1480/dfu/phy.c
new file mode 100644
index 00000000000..3b1a87de8e6
--- /dev/null
+++ b/drivers/uwb/i1480/dfu/phy.c
@@ -0,0 +1,203 @@
+/*
+ * Intel Wireless UWB Link 1480
+ * PHY parameters upload
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * Code for uploading the PHY parameters to the PHY through the UWB
+ * Radio Control interface.
+ *
+ * We just send the data through the MPI interface using HWA-like
+ * commands and then reset the PHY to make sure it is ok.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/usb/wusb.h>
+#include "i1480-dfu.h"
+
+
+/**
+ * Write a value array to an address of the MPI interface
+ *
+ * @i1480: Device descriptor
+ * @data: Data array to write
+ * @size: Size of the data array
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * The data array is organized into pairs:
+ *
+ * ADDRESS VALUE
+ *
+ * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has
+ * to be a multiple of three.
+ */
+static
+int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size)
+{
+ int result;
+ struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf;
+ struct i1480_evt_confirm *reply = i1480->evt_buf;
+
+ BUG_ON(size > 480);
+ result = -ENOMEM;
+ cmd->rccb.bCommandType = i1480_CET_VS1;
+ cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE);
+ cmd->size = cpu_to_le16(size);
+ memcpy(cmd->data, data, size);
+ reply->rceb.bEventType = i1480_CET_VS1;
+ reply->rceb.wEvent = i1480_CMD_MPI_WRITE;
+ result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply));
+ if (result < 0)
+ goto out;
+ if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n",
+ reply->bResultCode);
+ result = -EIO;
+ }
+out:
+ return result;
+}
+
+
+/**
+ * Read a value array to from an address of the MPI interface
+ *
+ * @i1480: Device descriptor
+ * @data: where to place the read array
+ * @srcaddr: Where to read from
+ * @size: Size of the data read array
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * The command data array is organized into pairs ADDR0 ADDR1..., and
+ * the returned data in ADDR0 VALUE0 ADDR1 VALUE1...
+ *
+ * We generate the command array to be a sequential read and then
+ * rearrange the result.
+ *
+ * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply.
+ *
+ * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount
+ * of values we can read is (512 - sizeof(*reply)) / 3
+ */
+static
+int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size)
+{
+ int result;
+ struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf;
+ struct i1480_evt_mpi_read *reply = i1480->evt_buf;
+ unsigned cnt;
+
+ memset(i1480->cmd_buf, 0x69, 512);
+ memset(i1480->evt_buf, 0x69, 512);
+
+ BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3);
+ result = -ENOMEM;
+ cmd->rccb.bCommandType = i1480_CET_VS1;
+ cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ);
+ cmd->size = cpu_to_le16(3*size);
+ for (cnt = 0; cnt < size; cnt++) {
+ cmd->data[cnt].page = (srcaddr + cnt) >> 8;
+ cmd->data[cnt].offset = (srcaddr + cnt) & 0xff;
+ }
+ reply->rceb.bEventType = i1480_CET_VS1;
+ reply->rceb.wEvent = i1480_CMD_MPI_READ;
+ result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size,
+ sizeof(*reply) + 3*size);
+ if (result < 0)
+ goto out;
+ if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n",
+ reply->bResultCode);
+ result = -EIO;
+ }
+ for (cnt = 0; cnt < size; cnt++) {
+ if (reply->data[cnt].page != (srcaddr + cnt) >> 8)
+ dev_err(i1480->dev, "MPI-READ: page inconsistency at "
+ "index %u: expected 0x%02x, got 0x%02x\n", cnt,
+ (srcaddr + cnt) >> 8, reply->data[cnt].page);
+ if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff))
+ dev_err(i1480->dev, "MPI-READ: offset inconsistency at "
+ "index %u: expected 0x%02x, got 0x%02x\n", cnt,
+ (srcaddr + cnt) & 0x00ff,
+ reply->data[cnt].offset);
+ data[cnt] = reply->data[cnt].value;
+ }
+ result = 0;
+out:
+ return result;
+}
+
+
+/**
+ * Upload a PHY firmware, wait for it to start
+ *
+ * @i1480: Device instance
+ * @fw_name: Name of the file that contains the firmware
+ *
+ * We assume the MAC fw is up and running. This means we can use the
+ * MPI interface to write the PHY firmware. Once done, we issue an
+ * MBOA Reset, which will force the MAC to reset and reinitialize the
+ * PHY. If that works, we are ready to go.
+ *
+ * Max packet size for the MPI write is 512, so the max buffer is 480
+ * (which gives us 160 byte triads of MSB, LSB and VAL for the data).
+ */
+int i1480_phy_fw_upload(struct i1480 *i1480)
+{
+ int result;
+ const struct firmware *fw;
+ const char *data_itr, *data_top;
+ const size_t MAX_BLK_SIZE = 480; /* 160 triads */
+ size_t data_size;
+ u8 phy_stat;
+
+ result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev);
+ if (result < 0)
+ goto out;
+ /* Loop writing data in chunks as big as possible until done. */
+ for (data_itr = fw->data, data_top = data_itr + fw->size;
+ data_itr < data_top; data_itr += MAX_BLK_SIZE) {
+ data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr));
+ result = i1480_mpi_write(i1480, data_itr, data_size);
+ if (result < 0)
+ goto error_mpi_write;
+ }
+ /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */
+ result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1);
+ if (result < 0) {
+ dev_err(i1480->dev, "PHY: can't get status: %d\n", result);
+ goto error_mpi_status;
+ }
+ if (phy_stat != 0) {
+ result = -ENODEV;
+ dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat);
+ goto error_phy_status;
+ }
+ dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name);
+error_phy_status:
+error_mpi_status:
+error_mpi_write:
+ release_firmware(fw);
+ if (result < 0)
+ dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), "
+ "power cycle device\n", i1480->phy_fw_name, result);
+out:
+ return result;
+}
diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c
new file mode 100644
index 00000000000..98eeeff051a
--- /dev/null
+++ b/drivers/uwb/i1480/dfu/usb.c
@@ -0,0 +1,500 @@
+/*
+ * Intel Wireless UWB Link 1480
+ * USB SKU firmware upload implementation
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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 driver will prepare the i1480 device to behave as a real
+ * Wireless USB HWA adaptor by uploading the firmware.
+ *
+ * When the device is connected or driver is loaded, i1480_usb_probe()
+ * is called--this will allocate and initialize the device structure,
+ * fill in the pointers to the common functions (read, write,
+ * wait_init_done and cmd for HWA command execution) and once that is
+ * done, call the common firmware uploading routine. Then clean up and
+ * return -ENODEV, as we don't attach to the device.
+ *
+ * The rest are the basic ops we implement that the fw upload code
+ * uses to do its job. All the ops in the common code are i1480->NAME,
+ * the functions are i1480_usb_NAME().
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/uwb.h>
+#include <linux/usb/wusb.h>
+#include <linux/usb/wusb-wa.h>
+#include "i1480-dfu.h"
+
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+
+struct i1480_usb {
+ struct i1480 i1480;
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+ struct urb *neep_urb; /* URB for reading from EP1 */
+};
+
+
+static
+void i1480_usb_init(struct i1480_usb *i1480_usb)
+{
+ i1480_init(&i1480_usb->i1480);
+}
+
+
+static
+int i1480_usb_create(struct i1480_usb *i1480_usb, struct usb_interface *iface)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+ int result = -ENOMEM;
+
+ i1480_usb->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */
+ i1480_usb->usb_iface = usb_get_intf(iface);
+ usb_set_intfdata(iface, i1480_usb); /* Bind the driver to iface0 */
+ i1480_usb->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (i1480_usb->neep_urb == NULL)
+ goto error;
+ return 0;
+
+error:
+ usb_set_intfdata(iface, NULL);
+ usb_put_intf(iface);
+ usb_put_dev(usb_dev);
+ return result;
+}
+
+
+static
+void i1480_usb_destroy(struct i1480_usb *i1480_usb)
+{
+ usb_kill_urb(i1480_usb->neep_urb);
+ usb_free_urb(i1480_usb->neep_urb);
+ usb_set_intfdata(i1480_usb->usb_iface, NULL);
+ usb_put_intf(i1480_usb->usb_iface);
+ usb_put_dev(i1480_usb->usb_dev);
+}
+
+
+/**
+ * Write a buffer to a memory address in the i1480 device
+ *
+ * @i1480: i1480 instance
+ * @memory_address:
+ * Address where to write the data buffer to.
+ * @buffer: Buffer to the data
+ * @size: Size of the buffer [has to be < 512].
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * Data buffers to USB cannot be on the stack or in vmalloc'ed areas,
+ * so we copy it to the local i1480 buffer before proceeding. In any
+ * case, we have a max size we can send, soooo.
+ */
+static
+int i1480_usb_write(struct i1480 *i1480, u32 memory_address,
+ const void *buffer, size_t size)
+{
+ int result = 0;
+ struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+ size_t buffer_size, itr = 0;
+
+ d_fnstart(3, i1480->dev, "(%p, 0x%08x, %p, %zu)\n",
+ i1480, memory_address, buffer, size);
+ BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
+ while (size > 0) {
+ buffer_size = size < i1480->buf_size ? size : i1480->buf_size;
+ memcpy(i1480->cmd_buf, buffer + itr, buffer_size);
+ result = usb_control_msg(
+ i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
+ 0xf0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ cpu_to_le16(memory_address & 0xffff),
+ cpu_to_le16((memory_address >> 16) & 0xffff),
+ i1480->cmd_buf, buffer_size, 100 /* FIXME: arbitrary */);
+ if (result < 0)
+ break;
+ d_printf(3, i1480->dev,
+ "wrote @ 0x%08x %u bytes (of %zu bytes requested)\n",
+ memory_address, result, buffer_size);
+ d_dump(4, i1480->dev, i1480->cmd_buf, result);
+ itr += result;
+ memory_address += result;
+ size -= result;
+ }
+ d_fnend(3, i1480->dev, "(%p, 0x%08x, %p, %zu) = %d\n",
+ i1480, memory_address, buffer, size, result);
+ return result;
+}
+
+
+/**
+ * Read a block [max size 512] of the device's memory to @i1480's buffer.
+ *
+ * @i1480: i1480 instance
+ * @memory_address:
+ * Address where to read from.
+ * @size: Size to read. Smaller than or equal to 512.
+ * @returns: >= 0 number of bytes written if ok, < 0 errno code on error.
+ *
+ * NOTE: if the memory address or block is incorrect, you might get a
+ * stall or a different memory read. Caller has to verify the
+ * memory address and size passed back in the @neh structure.
+ */
+static
+int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size)
+{
+ ssize_t result = 0, bytes = 0;
+ size_t itr, read_size = i1480->buf_size;
+ struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+
+ d_fnstart(3, i1480->dev, "(%p, 0x%08x, %zu)\n",
+ i1480, addr, size);
+ BUG_ON(size > i1480->buf_size);
+ BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
+ BUG_ON(read_size > 512);
+
+ if (addr >= 0x8000d200 && addr < 0x8000d400) /* Yeah, HW quirk */
+ read_size = 4;
+
+ for (itr = 0; itr < size; itr += read_size) {
+ size_t itr_addr = addr + itr;
+ size_t itr_size = min(read_size, size - itr);
+ result = usb_control_msg(
+ i1480_usb->usb_dev, usb_rcvctrlpipe(i1480_usb->usb_dev, 0),
+ 0xf0, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ cpu_to_le16(itr_addr & 0xffff),
+ cpu_to_le16((itr_addr >> 16) & 0xffff),
+ i1480->cmd_buf + itr, itr_size,
+ 100 /* FIXME: arbitrary */);
+ if (result < 0) {
+ dev_err(i1480->dev, "%s: USB read error: %zd\n",
+ __func__, result);
+ goto out;
+ }
+ if (result != itr_size) {
+ result = -EIO;
+ dev_err(i1480->dev,
+ "%s: partial read got only %zu bytes vs %zu expected\n",
+ __func__, result, itr_size);
+ goto out;
+ }
+ bytes += result;
+ }
+ result = bytes;
+out:
+ d_fnend(3, i1480->dev, "(%p, 0x%08x, %zu) = %zd\n",
+ i1480, addr, size, result);
+ if (result > 0)
+ d_dump(4, i1480->dev, i1480->cmd_buf, result);
+ return result;
+}
+
+
+/**
+ * Callback for reads on the notification/event endpoint
+ *
+ * Just enables the completion read handler.
+ */
+static
+void i1480_usb_neep_cb(struct urb *urb)
+{
+ struct i1480 *i1480 = urb->context;
+ struct device *dev = i1480->dev;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ECONNRESET: /* Not an error, but a controlled situation; */
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ dev_dbg(dev, "NEEP: reset/noent %d\n", urb->status);
+ break;
+ case -ESHUTDOWN: /* going away! */
+ dev_dbg(dev, "NEEP: down %d\n", urb->status);
+ break;
+ default:
+ dev_err(dev, "NEEP: unknown status %d\n", urb->status);
+ break;
+ }
+ i1480->evt_result = urb->actual_length;
+ complete(&i1480->evt_complete);
+ return;
+}
+
+
+/**
+ * Wait for the MAC FW to initialize
+ *
+ * MAC FW sends a 0xfd/0101/00 notification to EP1 when done
+ * initializing. Get that notification into i1480->evt_buf; upper layer
+ * will verify it.
+ *
+ * Set i1480->evt_result with the result of getting the event or its
+ * size (if succesful).
+ *
+ * Delivers the data directly to i1480->evt_buf
+ */
+static
+int i1480_usb_wait_init_done(struct i1480 *i1480)
+{
+ int result;
+ struct device *dev = i1480->dev;
+ struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+ struct usb_endpoint_descriptor *epd;
+
+ d_fnstart(3, dev, "(%p)\n", i1480);
+ init_completion(&i1480->evt_complete);
+ i1480->evt_result = -EINPROGRESS;
+ epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
+ usb_fill_int_urb(i1480_usb->neep_urb, i1480_usb->usb_dev,
+ usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
+ i1480->evt_buf, i1480->buf_size,
+ i1480_usb_neep_cb, i1480, epd->bInterval);
+ result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "init done: cannot submit NEEP read: %d\n",
+ result);
+ goto error_submit;
+ }
+ /* Wait for the USB callback to get the data */
+ result = wait_for_completion_interruptible_timeout(
+ &i1480->evt_complete, HZ);
+ if (result <= 0) {
+ result = result == 0 ? -ETIMEDOUT : result;
+ goto error_wait;
+ }
+ usb_kill_urb(i1480_usb->neep_urb);
+ d_fnend(3, dev, "(%p) = 0\n", i1480);
+ return 0;
+
+error_wait:
+ usb_kill_urb(i1480_usb->neep_urb);
+error_submit:
+ i1480->evt_result = result;
+ d_fnend(3, dev, "(%p) = %d\n", i1480, result);
+ return result;
+}
+
+
+/**
+ * Generic function for issuing commands to the i1480
+ *
+ * @i1480: i1480 instance
+ * @cmd_name: Name of the command (for error messages)
+ * @cmd: Pointer to command buffer
+ * @cmd_size: Size of the command buffer
+ * @reply: Buffer for the reply event
+ * @reply_size: Expected size back (including RCEB); the reply buffer
+ * is assumed to be as big as this.
+ * @returns: >= 0 size of the returned event data if ok,
+ * < 0 errno code on error.
+ *
+ * Arms the NE handle, issues the command to the device and checks the
+ * basics of the reply event.
+ */
+static
+int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size)
+{
+ int result;
+ struct device *dev = i1480->dev;
+ struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+ struct usb_endpoint_descriptor *epd;
+ struct uwb_rccb *cmd = i1480->cmd_buf;
+ u8 iface_no;
+
+ d_fnstart(3, dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size);
+ /* Post a read on the notification & event endpoint */
+ iface_no = i1480_usb->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+ epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
+ usb_fill_int_urb(
+ i1480_usb->neep_urb, i1480_usb->usb_dev,
+ usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
+ i1480->evt_buf, i1480->buf_size,
+ i1480_usb_neep_cb, i1480, epd->bInterval);
+ result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "%s: cannot submit NEEP read: %d\n",
+ cmd_name, result);
+ goto error_submit_ep1;
+ }
+ /* Now post the command on EP0 */
+ result = usb_control_msg(
+ i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
+ WA_EXEC_RC_CMD,
+ USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
+ 0, iface_no,
+ cmd, cmd_size,
+ 100 /* FIXME: this is totally arbitrary */);
+ if (result < 0) {
+ dev_err(dev, "%s: control request failed: %d\n",
+ cmd_name, result);
+ goto error_submit_ep0;
+ }
+ d_fnend(3, dev, "(%p, %s, %zu) = %d\n",
+ i1480, cmd_name, cmd_size, result);
+ return result;
+
+error_submit_ep0:
+ usb_kill_urb(i1480_usb->neep_urb);
+error_submit_ep1:
+ d_fnend(3, dev, "(%p, %s, %zu) = %d\n",
+ i1480, cmd_name, cmd_size, result);
+ return result;
+}
+
+
+/*
+ * Probe a i1480 device for uploading firmware.
+ *
+ * We attach only to interface #0, which is the radio control interface.
+ */
+static
+int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+ struct i1480_usb *i1480_usb;
+ struct i1480 *i1480;
+ struct device *dev = &iface->dev;
+ int result;
+
+ result = -ENODEV;
+ if (iface->cur_altsetting->desc.bInterfaceNumber != 0) {
+ dev_dbg(dev, "not attaching to iface %d\n",
+ iface->cur_altsetting->desc.bInterfaceNumber);
+ goto error;
+ }
+ if (iface->num_altsetting > 1
+ && interface_to_usbdev(iface)->descriptor.idProduct == 0xbabe) {
+ /* Need altsetting #1 [HW QUIRK] or EP1 won't work */
+ result = usb_set_interface(interface_to_usbdev(iface), 0, 1);
+ if (result < 0)
+ dev_warn(dev,
+ "can't set altsetting 1 on iface 0: %d\n",
+ result);
+ }
+
+ result = -ENOMEM;
+ i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL);
+ if (i1480_usb == NULL) {
+ dev_err(dev, "Unable to allocate instance\n");
+ goto error;
+ }
+ i1480_usb_init(i1480_usb);
+
+ i1480 = &i1480_usb->i1480;
+ i1480->buf_size = 512;
+ i1480->cmd_buf = kmalloc(2 * i1480->buf_size, GFP_KERNEL);
+ if (i1480->cmd_buf == NULL) {
+ dev_err(dev, "Cannot allocate transfer buffers\n");
+ result = -ENOMEM;
+ goto error_buf_alloc;
+ }
+ i1480->evt_buf = i1480->cmd_buf + i1480->buf_size;
+
+ result = i1480_usb_create(i1480_usb, iface);
+ if (result < 0) {
+ dev_err(dev, "Cannot create instance: %d\n", result);
+ goto error_create;
+ }
+
+ /* setup the fops and upload the firmare */
+ 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";
+ i1480->phy_fw_name = "i1480-phy-0.0.bin";
+ i1480->dev = &iface->dev;
+ i1480->write = i1480_usb_write;
+ i1480->read = i1480_usb_read;
+ i1480->rc_setup = NULL;
+ i1480->wait_init_done = i1480_usb_wait_init_done;
+ i1480->cmd = i1480_usb_cmd;
+
+ result = i1480_fw_upload(&i1480_usb->i1480); /* the real thing */
+ if (result >= 0) {
+ usb_reset_device(i1480_usb->usb_dev);
+ result = -ENODEV; /* we don't want to bind to the iface */
+ }
+ i1480_usb_destroy(i1480_usb);
+error_create:
+ kfree(i1480->cmd_buf);
+error_buf_alloc:
+ kfree(i1480_usb);
+error:
+ return result;
+}
+
+#define i1480_USB_DEV(v, p) \
+{ \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE \
+ | USB_DEVICE_ID_MATCH_DEV_INFO \
+ | USB_DEVICE_ID_MATCH_INT_INFO, \
+ .idVendor = (v), \
+ .idProduct = (p), \
+ .bDeviceClass = 0xff, \
+ .bDeviceSubClass = 0xff, \
+ .bDeviceProtocol = 0xff, \
+ .bInterfaceClass = 0xff, \
+ .bInterfaceSubClass = 0xff, \
+ .bInterfaceProtocol = 0xff, \
+}
+
+
+/** USB device ID's that we handle */
+static struct usb_device_id i1480_usb_id_table[] = {
+ i1480_USB_DEV(0x8086, 0xdf3b),
+ i1480_USB_DEV(0x15a9, 0x0005),
+ i1480_USB_DEV(0x07d1, 0x3802),
+ i1480_USB_DEV(0x050d, 0x305a),
+ i1480_USB_DEV(0x3495, 0x3007),
+ {},
+};
+MODULE_DEVICE_TABLE(usb, i1480_usb_id_table);
+
+
+static struct usb_driver i1480_dfu_driver = {
+ .name = "i1480-dfu-usb",
+ .id_table = i1480_usb_id_table,
+ .probe = i1480_usb_probe,
+ .disconnect = NULL,
+};
+
+
+/*
+ * Initialize the i1480 DFU driver.
+ *
+ * We also need to register our function for guessing event sizes.
+ */
+static int __init i1480_dfu_driver_init(void)
+{
+ return usb_register(&i1480_dfu_driver);
+}
+module_init(i1480_dfu_driver_init);
+
+
+static void __exit i1480_dfu_driver_exit(void)
+{
+ usb_deregister(&i1480_dfu_driver);
+}
+module_exit(i1480_dfu_driver_exit);
+
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Intel Wireless UWB Link 1480 firmware uploader for USB");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/i1480/i1480-est.c b/drivers/uwb/i1480/i1480-est.c
new file mode 100644
index 00000000000..7bf8c6febae
--- /dev/null
+++ b/drivers/uwb/i1480/i1480-est.c
@@ -0,0 +1,99 @@
+/*
+ * Intel Wireless UWB Link 1480
+ * Event Size tables for Wired Adaptors
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/uwb.h>
+#include "dfu/i1480-dfu.h"
+
+
+/** Event size table for wEvents 0x00XX */
+static struct uwb_est_entry i1480_est_fd00[] = {
+ /* Anybody expecting this response has to use
+ * neh->extra_size to specify the real size that will
+ * come back. */
+ [i1480_EVT_CONFIRM] = { .size = sizeof(struct i1480_evt_confirm) },
+ [i1480_CMD_SET_IP_MAS] = { .size = sizeof(struct i1480_evt_confirm) },
+#ifdef i1480_RCEB_EXTENDED
+ [0x09] = {
+ .size = sizeof(struct i1480_rceb),
+ .offset = 1 + offsetof(struct i1480_rceb, wParamLength),
+ },
+#endif
+};
+
+/** Event size table for wEvents 0x01XX */
+static struct uwb_est_entry i1480_est_fd01[] = {
+ [0xff & i1480_EVT_RM_INIT_DONE] = { .size = sizeof(struct i1480_rceb) },
+ [0xff & i1480_EVT_DEV_ADD] = { .size = sizeof(struct i1480_rceb) + 9 },
+ [0xff & i1480_EVT_DEV_RM] = { .size = sizeof(struct i1480_rceb) + 9 },
+ [0xff & i1480_EVT_DEV_ID_CHANGE] = {
+ .size = sizeof(struct i1480_rceb) + 2 },
+};
+
+static int i1480_est_init(void)
+{
+ int result = uwb_est_register(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
+ i1480_est_fd00,
+ ARRAY_SIZE(i1480_est_fd00));
+ if (result < 0) {
+ printk(KERN_ERR "Can't register EST table fd00: %d\n", result);
+ return result;
+ }
+ result = uwb_est_register(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b,
+ i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01));
+ if (result < 0) {
+ printk(KERN_ERR "Can't register EST table fd01: %d\n", result);
+ return result;
+ }
+ return 0;
+}
+module_init(i1480_est_init);
+
+static void i1480_est_exit(void)
+{
+ uwb_est_unregister(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
+ i1480_est_fd00, ARRAY_SIZE(i1480_est_fd00));
+ uwb_est_unregister(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b,
+ i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01));
+}
+module_exit(i1480_est_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("i1480's Vendor Specific Event Size Tables");
+MODULE_LICENSE("GPL");
+
+/**
+ * USB device ID's that we handle
+ *
+ * [so we are loaded when this kind device is connected]
+ */
+static struct usb_device_id i1480_est_id_table[] = {
+ { USB_DEVICE(0x8086, 0xdf3b), },
+ { USB_DEVICE(0x8086, 0x0c3b), },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, i1480_est_id_table);
diff --git a/drivers/uwb/i1480/i1480-wlp.h b/drivers/uwb/i1480/i1480-wlp.h
new file mode 100644
index 00000000000..18a8b0e4567
--- /dev/null
+++ b/drivers/uwb/i1480/i1480-wlp.h
@@ -0,0 +1,200 @@
+/*
+ * Intel 1480 Wireless UWB Link
+ * WLP specific definitions
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ */
+
+#ifndef __i1480_wlp_h__
+#define __i1480_wlp_h__
+
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/uwb.h>
+#include <linux/if_ether.h>
+#include <asm/byteorder.h>
+
+/* New simplified header format? */
+#undef WLP_HDR_FMT_2 /* FIXME: rename */
+
+/**
+ * Values of the Delivery ID & Type field when PCA or DRP
+ *
+ * The Delivery ID & Type field in the WLP TX header indicates whether
+ * the frame is PCA or DRP. This is done based on the high level bit of
+ * this field.
+ * We use this constant to test if the traffic is PCA or DRP as follows:
+ * if (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)
+ * this is DRP traffic
+ * else
+ * this is PCA traffic
+ */
+enum deliver_id_type_bit {
+ WLP_DRP = 8,
+};
+
+/**
+ * WLP TX header
+ *
+ * Indicates UWB/WLP-specific transmission parameters for a network
+ * packet.
+ */
+struct wlp_tx_hdr {
+ /* dword 0 */
+ struct uwb_dev_addr dstaddr;
+ u8 key_index;
+ u8 mac_params;
+ /* dword 1 */
+ u8 phy_params;
+#ifndef WLP_HDR_FMT_2
+ u8 reserved;
+ __le16 oui01; /* FIXME: not so sure if __le16 or u8[2] */
+ /* dword 2 */
+ u8 oui2; /* if all LE, it could be merged */
+ __le16 prid;
+#endif
+} __attribute__((packed));
+
+static inline int wlp_tx_hdr_delivery_id_type(const struct wlp_tx_hdr *hdr)
+{
+ return hdr->mac_params & 0x0f;
+}
+
+static inline int wlp_tx_hdr_ack_policy(const struct wlp_tx_hdr *hdr)
+{
+ return (hdr->mac_params >> 4) & 0x07;
+}
+
+static inline int wlp_tx_hdr_rts_cts(const struct wlp_tx_hdr *hdr)
+{
+ return (hdr->mac_params >> 7) & 0x01;
+}
+
+static inline void wlp_tx_hdr_set_delivery_id_type(struct wlp_tx_hdr *hdr, int id)
+{
+ hdr->mac_params = (hdr->mac_params & ~0x0f) | id;
+}
+
+static inline void wlp_tx_hdr_set_ack_policy(struct wlp_tx_hdr *hdr,
+ enum uwb_ack_pol policy)
+{
+ hdr->mac_params = (hdr->mac_params & ~0x70) | (policy << 4);
+}
+
+static inline void wlp_tx_hdr_set_rts_cts(struct wlp_tx_hdr *hdr, int rts_cts)
+{
+ hdr->mac_params = (hdr->mac_params & ~0x80) | (rts_cts << 7);
+}
+
+static inline enum uwb_phy_rate wlp_tx_hdr_phy_rate(const struct wlp_tx_hdr *hdr)
+{
+ return hdr->phy_params & 0x0f;
+}
+
+static inline int wlp_tx_hdr_tx_power(const struct wlp_tx_hdr *hdr)
+{
+ return (hdr->phy_params >> 4) & 0x0f;
+}
+
+static inline void wlp_tx_hdr_set_phy_rate(struct wlp_tx_hdr *hdr, enum uwb_phy_rate rate)
+{
+ hdr->phy_params = (hdr->phy_params & ~0x0f) | rate;
+}
+
+static inline void wlp_tx_hdr_set_tx_power(struct wlp_tx_hdr *hdr, int pwr)
+{
+ hdr->phy_params = (hdr->phy_params & ~0xf0) | (pwr << 4);
+}
+
+
+/**
+ * WLP RX header
+ *
+ * Provides UWB/WLP-specific transmission data for a received
+ * network packet.
+ */
+struct wlp_rx_hdr {
+ /* dword 0 */
+ struct uwb_dev_addr dstaddr;
+ struct uwb_dev_addr srcaddr;
+ /* dword 1 */
+ u8 LQI;
+ s8 RSSI;
+ u8 reserved3;
+#ifndef WLP_HDR_FMT_2
+ u8 oui0;
+ /* dword 2 */
+ __le16 oui12;
+ __le16 prid;
+#endif
+} __attribute__((packed));
+
+
+/** User configurable options for WLP */
+struct wlp_options {
+ struct mutex mutex; /* access to user configurable options*/
+ struct wlp_tx_hdr def_tx_hdr; /* default tx hdr */
+ u8 pca_base_priority;
+ u8 bw_alloc; /*index into bw_allocs[] for PCA/DRP reservations*/
+};
+
+
+static inline
+void wlp_options_init(struct wlp_options *options)
+{
+ mutex_init(&options->mutex);
+ wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, UWB_ACK_INM);
+ wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, 1);
+ /* FIXME: default to phy caps */
+ wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, UWB_PHY_RATE_480);
+#ifndef WLP_HDR_FMT_2
+ options->def_tx_hdr.prid = cpu_to_le16(0x0000);
+#endif
+}
+
+
+/* sysfs helpers */
+
+extern ssize_t uwb_pca_base_priority_store(struct wlp_options *,
+ const char *, size_t);
+extern ssize_t uwb_pca_base_priority_show(const struct wlp_options *, char *);
+extern ssize_t uwb_bw_alloc_store(struct wlp_options *, const char *, size_t);
+extern ssize_t uwb_bw_alloc_show(const struct wlp_options *, char *);
+extern ssize_t uwb_ack_policy_store(struct wlp_options *,
+ const char *, size_t);
+extern ssize_t uwb_ack_policy_show(const struct wlp_options *, char *);
+extern ssize_t uwb_rts_cts_store(struct wlp_options *, const char *, size_t);
+extern ssize_t uwb_rts_cts_show(const struct wlp_options *, char *);
+extern ssize_t uwb_phy_rate_store(struct wlp_options *, const char *, size_t);
+extern ssize_t uwb_phy_rate_show(const struct wlp_options *, char *);
+
+
+/** Simple bandwidth allocation (temporary and too simple) */
+struct wlp_bw_allocs {
+ const char *name;
+ struct {
+ u8 mask, stream;
+ } tx, rx;
+};
+
+
+#endif /* #ifndef __i1480_wlp_h__ */
diff --git a/drivers/uwb/i1480/i1480u-wlp/Makefile b/drivers/uwb/i1480/i1480u-wlp/Makefile
new file mode 100644
index 00000000000..fe6709b8e68
--- /dev/null
+++ b/drivers/uwb/i1480/i1480u-wlp/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp.o
+
+i1480u-wlp-objs := \
+ lc.o \
+ netdev.o \
+ rx.o \
+ sysfs.o \
+ tx.o
diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h
new file mode 100644
index 00000000000..5f1b2951bb8
--- /dev/null
+++ b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h
@@ -0,0 +1,284 @@
+/*
+ * Intel 1480 Wireless UWB Link USB
+ * Header formats, constants, general internal interfaces
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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 is not an standard interface.
+ *
+ * FIXME: docs
+ *
+ * i1480u-wlp is pretty simple: two endpoints, one for tx, one for
+ * rx. rx is polled. Network packets (ethernet, whatever) are wrapped
+ * in i1480 TX or RX headers (for sending over the air), and these
+ * packets are wrapped in UNTD headers (for sending to the WLP UWB
+ * controller).
+ *
+ * UNTD packets (UNTD hdr + i1480 hdr + network packet) packets
+ * cannot be bigger than i1480u_MAX_FRG_SIZE. When this happens, the
+ * i1480 packet is broken in chunks/packets:
+ *
+ * UNTD-1st.hdr + i1480.hdr + payload
+ * UNTD-next.hdr + payload
+ * ...
+ * UNTD-last.hdr + payload
+ *
+ * so that each packet is smaller or equal than i1480u_MAX_FRG_SIZE.
+ *
+ * All HW structures and bitmaps are little endian, so we need to play
+ * ugly tricks when defining bitfields. Hoping for the day GCC
+ * implements __attribute__((endian(1234))).
+ *
+ * FIXME: ROADMAP to the whole implementation
+ */
+
+#ifndef __i1480u_wlp_h__
+#define __i1480u_wlp_h__
+
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/uwb.h> /* struct uwb_rc, struct uwb_notifs_handler */
+#include <linux/wlp.h>
+#include "../i1480-wlp.h"
+
+#undef i1480u_FLOW_CONTROL /* Enable flow control code */
+
+/**
+ * Basic flow control
+ */
+enum {
+ i1480u_TX_INFLIGHT_MAX = 1000,
+ i1480u_TX_INFLIGHT_THRESHOLD = 100,
+};
+
+/** Maximum size of a transaction that we can tx/rx */
+enum {
+ /* Maximum packet size computed as follows: max UNTD header (8) +
+ * i1480 RX header (8) + max Ethernet header and payload (4096) +
+ * Padding added by skb_reserve (2) to make post Ethernet payload
+ * start on 16 byte boundary*/
+ i1480u_MAX_RX_PKT_SIZE = 4114,
+ i1480u_MAX_FRG_SIZE = 512,
+ i1480u_RX_BUFS = 9,
+};
+
+
+/**
+ * UNTD packet type
+ *
+ * We need to fragment any payload whose UNTD packet is going to be
+ * bigger than i1480u_MAX_FRG_SIZE.
+ */
+enum i1480u_pkt_type {
+ i1480u_PKT_FRAG_1ST = 0x1,
+ i1480u_PKT_FRAG_NXT = 0x0,
+ i1480u_PKT_FRAG_LST = 0x2,
+ i1480u_PKT_FRAG_CMP = 0x3
+};
+enum {
+ i1480u_PKT_NONE = 0x4,
+};
+
+/** USB Network Transfer Descriptor - common */
+struct untd_hdr {
+ u8 type;
+ __le16 len;
+} __attribute__((packed));
+
+static inline enum i1480u_pkt_type untd_hdr_type(const struct untd_hdr *hdr)
+{
+ return hdr->type & 0x03;
+}
+
+static inline int untd_hdr_rx_tx(const struct untd_hdr *hdr)
+{
+ return (hdr->type >> 2) & 0x01;
+}
+
+static inline void untd_hdr_set_type(struct untd_hdr *hdr, enum i1480u_pkt_type type)
+{
+ hdr->type = (hdr->type & ~0x03) | type;
+}
+
+static inline void untd_hdr_set_rx_tx(struct untd_hdr *hdr, int rx_tx)
+{
+ hdr->type = (hdr->type & ~0x04) | (rx_tx << 2);
+}
+
+
+/**
+ * USB Network Transfer Descriptor - Complete Packet
+ *
+ * This is for a packet that is smaller (header + payload) than
+ * i1480u_MAX_FRG_SIZE.
+ *
+ * @hdr.total_len is the size of the payload; the payload doesn't
+ * count this header nor the padding, but includes the size of i1480
+ * header.
+ */
+struct untd_hdr_cmp {
+ struct untd_hdr hdr;
+ u8 padding;
+} __attribute__((packed));
+
+
+/**
+ * USB Network Transfer Descriptor - First fragment
+ *
+ * @hdr.len is the size of the *whole packet* (excluding UNTD
+ * headers); @fragment_len is the size of the payload (excluding UNTD
+ * headers, but including i1480 headers).
+ */
+struct untd_hdr_1st {
+ struct untd_hdr hdr;
+ __le16 fragment_len;
+ u8 padding[3];
+} __attribute__((packed));
+
+
+/**
+ * USB Network Transfer Descriptor - Next / Last [Rest]
+ *
+ * @hdr.len is the size of the payload, not including headrs.
+ */
+struct untd_hdr_rst {
+ struct untd_hdr hdr;
+ u8 padding;
+} __attribute__((packed));
+
+
+/**
+ * Transmission context
+ *
+ * Wraps all the stuff needed to track a pending/active tx
+ * operation.
+ */
+struct i1480u_tx {
+ struct list_head list_node;
+ struct i1480u *i1480u;
+ struct urb *urb;
+
+ struct sk_buff *skb;
+ struct wlp_tx_hdr *wlp_tx_hdr;
+
+ void *buf; /* if NULL, no new buf was used */
+ size_t buf_size;
+};
+
+/**
+ * Basic flow control
+ *
+ * We maintain a basic flow control counter. "count" how many TX URBs are
+ * outstanding. Only allow "max"
+ * TX URBs to be outstanding. If this value is reached the queue will be
+ * stopped. The queue will be restarted when there are
+ * "threshold" URBs outstanding.
+ * Maintain a counter of how many time the TX queue needed to be restarted
+ * due to the "max" being exceeded and the "threshold" reached again. The
+ * timestamp "restart_ts" is to keep track from when the counter was last
+ * queried (see sysfs handling of file wlp_tx_inflight).
+ */
+struct i1480u_tx_inflight {
+ atomic_t count;
+ unsigned long max;
+ unsigned long threshold;
+ unsigned long restart_ts;
+ atomic_t restart_count;
+};
+
+/**
+ * Instance of a i1480u WLP interface
+ *
+ * Keeps references to the USB device that wraps it, as well as it's
+ * interface and associated UWB host controller. As well, it also
+ * keeps a link to the netdevice for integration into the networking
+ * stack.
+ * We maintian separate error history for the tx and rx endpoints because
+ * the implementation does not rely on locking - having one shared
+ * structure between endpoints may cause problems. Adding locking to the
+ * implementation will have higher cost than adding a separate structure.
+ */
+struct i1480u {
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+ struct net_device *net_dev;
+
+ spinlock_t lock;
+ struct net_device_stats stats;
+
+ /* RX context handling */
+ struct sk_buff *rx_skb;
+ struct uwb_dev_addr rx_srcaddr;
+ size_t rx_untd_pkt_size;
+ struct i1480u_rx_buf {
+ struct i1480u *i1480u; /* back pointer */
+ struct urb *urb;
+ struct sk_buff *data; /* i1480u_MAX_RX_PKT_SIZE each */
+ } rx_buf[i1480u_RX_BUFS]; /* N bufs */
+
+ spinlock_t tx_list_lock; /* TX context */
+ struct list_head tx_list;
+ u8 tx_stream;
+
+ struct stats lqe_stats, rssi_stats; /* radio statistics */
+
+ /* Options we can set from sysfs */
+ struct wlp_options options;
+ struct uwb_notifs_handler uwb_notifs_handler;
+ struct edc tx_errors;
+ struct edc rx_errors;
+ struct wlp wlp;
+#ifdef i1480u_FLOW_CONTROL
+ struct urb *notif_urb;
+ struct edc notif_edc; /* error density counter */
+ u8 notif_buffer[1];
+#endif
+ struct i1480u_tx_inflight tx_inflight;
+};
+
+/* Internal interfaces */
+extern void i1480u_rx_cb(struct urb *urb);
+extern int i1480u_rx_setup(struct i1480u *);
+extern void i1480u_rx_release(struct i1480u *);
+extern void i1480u_tx_release(struct i1480u *);
+extern int i1480u_xmit_frame(struct wlp *, struct sk_buff *,
+ struct uwb_dev_addr *);
+extern void i1480u_stop_queue(struct wlp *);
+extern void i1480u_start_queue(struct wlp *);
+extern int i1480u_sysfs_setup(struct i1480u *);
+extern void i1480u_sysfs_release(struct i1480u *);
+
+/* netdev interface */
+extern int i1480u_open(struct net_device *);
+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);
+
+/* bandwidth allocation callback */
+extern void i1480u_bw_alloc_cb(struct uwb_rsv *);
+
+/* Sys FS */
+extern struct attribute_group i1480u_wlp_attr_group;
+
+#endif /* #ifndef __i1480u_wlp_h__ */
diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c
new file mode 100644
index 00000000000..737d60cd5b7
--- /dev/null
+++ b/drivers/uwb/i1480/i1480u-wlp/lc.c
@@ -0,0 +1,421 @@
+/*
+ * WUSB Wire Adapter: WLP interface
+ * Driver for the Linux Network stack.
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ *
+ * This implements a very simple network driver for the WLP USB
+ * device that is associated to a UWB (Ultra Wide Band) host.
+ *
+ * This is seen as an interface of a composite device. Once the UWB
+ * host has an association to another WLP capable device, the
+ * networking interface (aka WLP) can start to send packets back and
+ * forth.
+ *
+ * Limitations:
+ *
+ * - Hand cranked; can't ifup the interface until there is an association
+ *
+ * - BW allocation very simplistic [see i1480u_mas_set() and callees].
+ *
+ *
+ * ROADMAP:
+ *
+ * ENTRY POINTS (driver model):
+ *
+ * i1480u_driver_{exit,init}(): initialization of the driver.
+ *
+ * i1480u_probe(): called by the driver code when a device
+ * matching 'i1480u_id_table' is connected.
+ *
+ * This allocs a netdev instance, inits with
+ * i1480u_add(), then registers_netdev().
+ * i1480u_init()
+ * i1480u_add()
+ *
+ * i1480u_disconnect(): device has been disconnected/module
+ * is being removed.
+ * i1480u_rm()
+ */
+#include <linux/version.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/uwb/debug.h>
+#include "i1480u-wlp.h"
+
+
+
+static inline
+void i1480u_init(struct i1480u *i1480u)
+{
+ /* nothing so far... doesn't it suck? */
+ spin_lock_init(&i1480u->lock);
+ INIT_LIST_HEAD(&i1480u->tx_list);
+ spin_lock_init(&i1480u->tx_list_lock);
+ wlp_options_init(&i1480u->options);
+ edc_init(&i1480u->tx_errors);
+ edc_init(&i1480u->rx_errors);
+#ifdef i1480u_FLOW_CONTROL
+ edc_init(&i1480u->notif_edc);
+#endif
+ stats_init(&i1480u->lqe_stats);
+ stats_init(&i1480u->rssi_stats);
+ wlp_init(&i1480u->wlp);
+}
+
+/**
+ * Fill WLP device information structure
+ *
+ * The structure will contain a few character arrays, each ending with a
+ * null terminated string. Each string has to fit (excluding terminating
+ * character) into a specified range obtained from the WLP substack.
+ *
+ * It is still not clear exactly how this device information should be
+ * obtained. Until we find out we use the USB device descriptor as backup, some
+ * information elements have intuitive mappings, other not.
+ */
+static
+void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info)
+{
+ struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
+ struct usb_device *usb_dev = i1480u->usb_dev;
+ /* Treat device name and model name the same */
+ if (usb_dev->descriptor.iProduct) {
+ usb_string(usb_dev, usb_dev->descriptor.iProduct,
+ dev_info->name, sizeof(dev_info->name));
+ usb_string(usb_dev, usb_dev->descriptor.iProduct,
+ dev_info->model_name, sizeof(dev_info->model_name));
+ }
+ if (usb_dev->descriptor.iManufacturer)
+ usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
+ dev_info->manufacturer,
+ sizeof(dev_info->manufacturer));
+ scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x",
+ __le16_to_cpu(usb_dev->descriptor.bcdDevice));
+ if (usb_dev->descriptor.iSerialNumber)
+ usb_string(usb_dev, usb_dev->descriptor.iSerialNumber,
+ dev_info->serial, sizeof(dev_info->serial));
+ /* FIXME: where should we obtain category? */
+ dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER);
+ /* FIXME: Complete OUI and OUIsubdiv attributes */
+}
+
+#ifdef i1480u_FLOW_CONTROL
+/**
+ * Callback for the notification endpoint
+ *
+ * This mostly controls the xon/xoff protocol. In case of hard error,
+ * we stop the queue. If not, we always retry.
+ */
+static
+void i1480u_notif_cb(struct urb *urb, struct pt_regs *regs)
+{
+ struct i1480u *i1480u = urb->context;
+ struct usb_interface *usb_iface = i1480u->usb_iface;
+ struct device *dev = &usb_iface->dev;
+ int result;
+
+ switch (urb->status) {
+ case 0: /* Got valid data, do xon/xoff */
+ switch (i1480u->notif_buffer[0]) {
+ case 'N':
+ dev_err(dev, "XOFF STOPPING queue at %lu\n", jiffies);
+ netif_stop_queue(i1480u->net_dev);
+ break;
+ case 'A':
+ dev_err(dev, "XON STARTING queue at %lu\n", jiffies);
+ netif_start_queue(i1480u->net_dev);
+ break;
+ default:
+ dev_err(dev, "NEP: unknown data 0x%02hhx\n",
+ i1480u->notif_buffer[0]);
+ }
+ break;
+ case -ECONNRESET: /* Controlled situation ... */
+ case -ENOENT: /* we killed the URB... */
+ dev_err(dev, "NEP: URB reset/noent %d\n", urb->status);
+ goto error;
+ case -ESHUTDOWN: /* going away! */
+ dev_err(dev, "NEP: URB down %d\n", urb->status);
+ goto error;
+ default: /* Retry unless it gets ugly */
+ if (edc_inc(&i1480u->notif_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "NEP: URB max acceptable errors "
+ "exceeded; resetting device\n");
+ goto error_reset;
+ }
+ dev_err(dev, "NEP: URB error %d\n", urb->status);
+ break;
+ }
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "NEP: Can't resubmit URB: %d; resetting device\n",
+ result);
+ goto error_reset;
+ }
+ return;
+
+error_reset:
+ wlp_reset_all(&i1480-wlp);
+error:
+ netif_stop_queue(i1480u->net_dev);
+ return;
+}
+#endif
+
+static
+int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface)
+{
+ int result = -ENODEV;
+ struct wlp *wlp = &i1480u->wlp;
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+ struct net_device *net_dev = i1480u->net_dev;
+ struct uwb_rc *rc;
+ struct uwb_dev *uwb_dev;
+#ifdef i1480u_FLOW_CONTROL
+ struct usb_endpoint_descriptor *epd;
+#endif
+
+ i1480u->usb_dev = usb_get_dev(usb_dev);
+ i1480u->usb_iface = iface;
+ rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev);
+ if (rc == NULL) {
+ dev_err(&iface->dev, "Cannot get associated UWB Radio "
+ "Controller\n");
+ goto out;
+ }
+ wlp->xmit_frame = i1480u_xmit_frame;
+ wlp->fill_device_info = i1480u_fill_device_info;
+ wlp->stop_queue = i1480u_stop_queue;
+ wlp->start_queue = i1480u_start_queue;
+ result = wlp_setup(wlp, rc);
+ if (result < 0) {
+ dev_err(&iface->dev, "Cannot setup WLP\n");
+ goto error_wlp_setup;
+ }
+ result = 0;
+ ether_setup(net_dev); /* make it an etherdevice */
+ uwb_dev = &rc->uwb_dev;
+ /* FIXME: hookup address change notifications? */
+
+ memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data,
+ sizeof(net_dev->dev_addr));
+
+ net_dev->hard_header_len = sizeof(struct untd_hdr_cmp)
+ + sizeof(struct wlp_tx_hdr)
+ + WLP_DATA_HLEN
+ + ETH_HLEN;
+ net_dev->mtu = 3500;
+ net_dev->tx_queue_len = 20; /* FIXME: maybe use 1000? */
+
+/* net_dev->flags &= ~IFF_BROADCAST; FIXME: BUG in firmware */
+ /* FIXME: multicast disabled */
+ net_dev->flags &= ~IFF_MULTICAST;
+ net_dev->features &= ~NETIF_F_SG;
+ net_dev->features &= ~NETIF_F_FRAGLIST;
+ /* All NETIF_F_*_CSUM disabled */
+ 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;
+
+#ifdef i1480u_FLOW_CONTROL
+ /* Notification endpoint setup (submitted when we open the device) */
+ i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (i1480u->notif_urb == NULL) {
+ dev_err(&iface->dev, "Unable to allocate notification URB\n");
+ result = -ENOMEM;
+ goto error_urb_alloc;
+ }
+ epd = &iface->cur_altsetting->endpoint[0].desc;
+ usb_fill_int_urb(i1480u->notif_urb, usb_dev,
+ usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
+ i1480u->notif_buffer, sizeof(i1480u->notif_buffer),
+ i1480u_notif_cb, i1480u, epd->bInterval);
+
+#endif
+
+ i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX;
+ i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD;
+ i1480u->tx_inflight.restart_ts = jiffies;
+ usb_set_intfdata(iface, i1480u);
+ return result;
+
+#ifdef i1480u_FLOW_CONTROL
+error_urb_alloc:
+#endif
+ wlp_remove(wlp);
+error_wlp_setup:
+ uwb_rc_put(rc);
+out:
+ usb_put_dev(i1480u->usb_dev);
+ return result;
+}
+
+static void i1480u_rm(struct i1480u *i1480u)
+{
+ struct uwb_rc *rc = i1480u->wlp.rc;
+ usb_set_intfdata(i1480u->usb_iface, NULL);
+#ifdef i1480u_FLOW_CONTROL
+ usb_kill_urb(i1480u->notif_urb);
+ usb_free_urb(i1480u->notif_urb);
+#endif
+ wlp_remove(&i1480u->wlp);
+ uwb_rc_put(rc);
+ usb_put_dev(i1480u->usb_dev);
+}
+
+/** Just setup @net_dev's i1480u private data */
+static void i1480u_netdev_setup(struct net_device *net_dev)
+{
+ struct i1480u *i1480u = netdev_priv(net_dev);
+ /* Initialize @i1480u */
+ memset(i1480u, 0, sizeof(*i1480u));
+ i1480u_init(i1480u);
+}
+
+/**
+ * Probe a i1480u 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.
+ *
+ * Does basic housekeeping stuff and then allocs a netdev with space
+ * for the i1480u data. Initializes, registers in i1480u, registers in
+ * netdev, ready to go.
+ */
+static int i1480u_probe(struct usb_interface *iface,
+ const struct usb_device_id *id)
+{
+ int result;
+ struct net_device *net_dev;
+ struct device *dev = &iface->dev;
+ struct i1480u *i1480u;
+
+ /* Allocate instance [calls i1480u_netdev_setup() on it] */
+ result = -ENOMEM;
+ net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_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);
+ i1480u = netdev_priv(net_dev);
+ i1480u->net_dev = net_dev;
+ result = i1480u_add(i1480u, iface); /* Now setup all the wlp stuff */
+ if (result < 0) {
+ dev_err(dev, "cannot add i1480u device: %d\n", result);
+ goto error_i1480u_add;
+ }
+ result = register_netdev(net_dev); /* Okey dokey, bring it up */
+ if (result < 0) {
+ dev_err(dev, "cannot register network device: %d\n", result);
+ goto error_register_netdev;
+ }
+ i1480u_sysfs_setup(i1480u);
+ if (result < 0)
+ goto error_sysfs_init;
+ return 0;
+
+error_sysfs_init:
+ unregister_netdev(net_dev);
+error_register_netdev:
+ i1480u_rm(i1480u);
+error_i1480u_add:
+ free_netdev(net_dev);
+error_alloc_netdev:
+ return result;
+}
+
+
+/**
+ * Disconect a i1480u from the system.
+ *
+ * i1480u_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 i1480u, free and kill.
+ */
+static void i1480u_disconnect(struct usb_interface *iface)
+{
+ struct i1480u *i1480u;
+ struct net_device *net_dev;
+
+ i1480u = usb_get_intfdata(iface);
+ net_dev = i1480u->net_dev;
+ netif_stop_queue(net_dev);
+#ifdef i1480u_FLOW_CONTROL
+ usb_kill_urb(i1480u->notif_urb);
+#endif
+ i1480u_sysfs_release(i1480u);
+ unregister_netdev(net_dev);
+ i1480u_rm(i1480u);
+ free_netdev(net_dev);
+}
+
+static struct usb_device_id i1480u_id_table[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE \
+ | USB_DEVICE_ID_MATCH_DEV_INFO \
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x8086,
+ .idProduct = 0x0c3b,
+ .bDeviceClass = 0xef,
+ .bDeviceSubClass = 0x02,
+ .bDeviceProtocol = 0x02,
+ .bInterfaceClass = 0xff,
+ .bInterfaceSubClass = 0xff,
+ .bInterfaceProtocol = 0xff,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(usb, i1480u_id_table);
+
+static struct usb_driver i1480u_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = i1480u_probe,
+ .disconnect = i1480u_disconnect,
+ .id_table = i1480u_id_table,
+};
+
+static int __init i1480u_driver_init(void)
+{
+ return usb_register(&i1480u_driver);
+}
+module_init(i1480u_driver_init);
+
+
+static void __exit i1480u_driver_exit(void)
+{
+ usb_deregister(&i1480u_driver);
+}
+module_exit(i1480u_driver_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("i1480 Wireless UWB Link WLP networking for USB");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/i1480/i1480u-wlp/netdev.c b/drivers/uwb/i1480/i1480u-wlp/netdev.c
new file mode 100644
index 00000000000..8802ac43d87
--- /dev/null
+++ b/drivers/uwb/i1480/i1480u-wlp/netdev.c
@@ -0,0 +1,368 @@
+/*
+ * WUSB Wire Adapter: WLP interface
+ * Driver for the Linux Network stack.
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ *
+ * Implementation of the netdevice linkage (except tx and rx related stuff).
+ *
+ * ROADMAP:
+ *
+ * ENTRY POINTS (Net device):
+ *
+ * i1480u_open(): Called when we ifconfig up the interface;
+ * associates to a UWB host controller, reserves
+ * bandwidth (MAS), sets up RX USB URB and starts
+ * the queue.
+ *
+ * i1480u_stop(): Called when we ifconfig down a interface;
+ * reverses _open().
+ *
+ * i1480u_set_config():
+ */
+
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/uwb/debug.h>
+#include "i1480u-wlp.h"
+
+struct i1480u_cmd_set_ip_mas {
+ struct uwb_rccb rccb;
+ struct uwb_dev_addr addr;
+ u8 stream;
+ u8 owner;
+ u8 type; /* enum uwb_drp_type */
+ u8 baMAS[32];
+} __attribute__((packed));
+
+
+static
+int i1480u_set_ip_mas(
+ struct uwb_rc *rc,
+ const struct uwb_dev_addr *dstaddr,
+ u8 stream, u8 owner, u8 type, unsigned long *mas)
+{
+
+ int result;
+ struct i1480u_cmd_set_ip_mas *cmd;
+ struct uwb_rc_evt_confirm reply;
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_kzalloc;
+ cmd->rccb.bCommandType = 0xfd;
+ cmd->rccb.wCommand = cpu_to_le16(0x000e);
+ cmd->addr = *dstaddr;
+ cmd->stream = stream;
+ cmd->owner = owner;
+ cmd->type = type;
+ if (mas == NULL)
+ memset(cmd->baMAS, 0x00, sizeof(cmd->baMAS));
+ else
+ memcpy(cmd->baMAS, mas, sizeof(cmd->baMAS));
+ reply.rceb.bEventType = 0xfd;
+ reply.rceb.wEvent = cpu_to_le16(0x000e);
+ result = uwb_rc_cmd(rc, "SET-IP-MAS", &cmd->rccb, sizeof(*cmd),
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ if (reply.bResultCode != UWB_RC_RES_FAIL) {
+ dev_err(&rc->uwb_dev.dev,
+ "SET-IP-MAS: command execution failed: %d\n",
+ reply.bResultCode);
+ result = -EIO;
+ }
+error_cmd:
+ kfree(cmd);
+error_kzalloc:
+ return result;
+}
+
+/*
+ * Inform a WLP interface of a MAS reservation
+ *
+ * @rc is assumed refcnted.
+ */
+/* FIXME: detect if remote device is WLP capable? */
+static int i1480u_mas_set_dev(struct uwb_dev *uwb_dev, struct uwb_rc *rc,
+ u8 stream, u8 owner, u8 type, unsigned long *mas)
+{
+ int result = 0;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ result = i1480u_set_ip_mas(rc, &uwb_dev->dev_addr, stream, owner,
+ type, mas);
+ if (result < 0) {
+ char rcaddrbuf[UWB_ADDR_STRSIZE], devaddrbuf[UWB_ADDR_STRSIZE];
+ uwb_dev_addr_print(rcaddrbuf, sizeof(rcaddrbuf),
+ &rc->uwb_dev.dev_addr);
+ uwb_dev_addr_print(devaddrbuf, sizeof(devaddrbuf),
+ &uwb_dev->dev_addr);
+ dev_err(dev, "Set IP MAS (%s to %s) failed: %d\n",
+ rcaddrbuf, devaddrbuf, result);
+ }
+ return result;
+}
+
+/**
+ * Called by bandwidth allocator when change occurs in reservation.
+ *
+ * @rsv: The reservation that is being established, modified, or
+ * terminated.
+ *
+ * When a reservation is established, modified, or terminated the upper layer
+ * (WLP here) needs set/update the currently available Media Access Slots
+ * that can be use for IP traffic.
+ *
+ * Our action taken during failure depends on how the reservation is being
+ * changed:
+ * - if reservation is being established we do nothing if we cannot set the
+ * new MAS to be used
+ * - if reservation is being terminated we revert back to PCA whether the
+ * SET IP MAS command succeeds or not.
+ */
+void i1480u_bw_alloc_cb(struct uwb_rsv *rsv)
+{
+ int result = 0;
+ struct i1480u *i1480u = rsv->pal_priv;
+ struct device *dev = &i1480u->usb_iface->dev;
+ struct uwb_dev *target_dev = rsv->target.dev;
+ struct uwb_rc *rc = i1480u->wlp.rc;
+ u8 stream = rsv->stream;
+ int type = rsv->type;
+ int is_owner = rsv->owner == &rc->uwb_dev;
+ unsigned long *bmp = rsv->mas.bm;
+
+ dev_err(dev, "WLP callback called - sending set ip mas\n");
+ /*user cannot change options while setting configuration*/
+ mutex_lock(&i1480u->options.mutex);
+ switch (rsv->state) {
+ case UWB_RSV_STATE_T_ACCEPTED:
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner,
+ type, bmp);
+ if (result < 0) {
+ dev_err(dev, "MAS reservation failed: %d\n", result);
+ goto out;
+ }
+ if (is_owner) {
+ wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr,
+ WLP_DRP | stream);
+ wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 0);
+ }
+ break;
+ case UWB_RSV_STATE_NONE:
+ /* revert back to PCA */
+ result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner,
+ type, bmp);
+ if (result < 0)
+ dev_err(dev, "MAS reservation failed: %d\n", result);
+ /* Revert to PCA even though SET IP MAS failed. */
+ wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr,
+ i1480u->options.pca_base_priority);
+ wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 1);
+ break;
+ default:
+ dev_err(dev, "unexpected WLP reservation state: %s (%d).\n",
+ uwb_rsv_state_str(rsv->state), rsv->state);
+ break;
+ }
+out:
+ mutex_unlock(&i1480u->options.mutex);
+ return;
+}
+
+/**
+ *
+ * Called on 'ifconfig up'
+ */
+int i1480u_open(struct net_device *net_dev)
+{
+ int result;
+ struct i1480u *i1480u = netdev_priv(net_dev);
+ struct wlp *wlp = &i1480u->wlp;
+ struct uwb_rc *rc;
+ struct device *dev = &i1480u->usb_iface->dev;
+
+ rc = wlp->rc;
+ result = i1480u_rx_setup(i1480u); /* Alloc RX stuff */
+ if (result < 0)
+ goto error_rx_setup;
+ netif_wake_queue(net_dev);
+#ifdef i1480u_FLOW_CONTROL
+ result = usb_submit_urb(i1480u->notif_urb, GFP_KERNEL);;
+ if (result < 0) {
+ dev_err(dev, "Can't submit notification URB: %d\n", result);
+ goto error_notif_urb_submit;
+ }
+#endif
+ i1480u->uwb_notifs_handler.cb = i1480u_uwb_notifs_cb;
+ i1480u->uwb_notifs_handler.data = i1480u;
+ if (uwb_bg_joined(rc))
+ netif_carrier_on(net_dev);
+ else
+ netif_carrier_off(net_dev);
+ uwb_notifs_register(rc, &i1480u->uwb_notifs_handler);
+ /* Interface is up with an address, now we can create WSS */
+ result = wlp_wss_setup(net_dev, &wlp->wss);
+ if (result < 0) {
+ dev_err(dev, "Can't create WSS: %d. \n", result);
+ goto error_notif_deregister;
+ }
+ return 0;
+error_notif_deregister:
+ uwb_notifs_deregister(rc, &i1480u->uwb_notifs_handler);
+#ifdef i1480u_FLOW_CONTROL
+error_notif_urb_submit:
+#endif
+ netif_stop_queue(net_dev);
+ i1480u_rx_release(i1480u);
+error_rx_setup:
+ return result;
+}
+
+
+/**
+ * Called on 'ifconfig down'
+ */
+int i1480u_stop(struct net_device *net_dev)
+{
+ struct i1480u *i1480u = netdev_priv(net_dev);
+ struct wlp *wlp = &i1480u->wlp;
+ struct uwb_rc *rc = wlp->rc;
+
+ BUG_ON(wlp->rc == NULL);
+ wlp_wss_remove(&wlp->wss);
+ uwb_notifs_deregister(rc, &i1480u->uwb_notifs_handler);
+ netif_carrier_off(net_dev);
+#ifdef i1480u_FLOW_CONTROL
+ usb_kill_urb(i1480u->notif_urb);
+#endif
+ netif_stop_queue(net_dev);
+ i1480u_rx_release(i1480u);
+ i1480u_tx_release(i1480u);
+ 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.
+ */
+int i1480u_set_config(struct net_device *net_dev, struct ifmap *map)
+{
+ int result;
+ struct i1480u *i1480u = netdev_priv(net_dev);
+ BUG_ON(i1480u->wlp.rc == NULL);
+ result = 0;
+ return result;
+}
+
+/**
+ * Change the MTU of the interface
+ */
+int i1480u_change_mtu(struct net_device *net_dev, int mtu)
+{
+ static union {
+ struct wlp_tx_hdr tx;
+ struct wlp_rx_hdr rx;
+ } i1480u_all_hdrs;
+
+ if (mtu < ETH_HLEN) /* We encap eth frames */
+ return -ERANGE;
+ if (mtu > 4000 - sizeof(i1480u_all_hdrs))
+ return -ERANGE;
+ net_dev->mtu = mtu;
+ return 0;
+}
+
+
+/**
+ * Callback function to handle events from UWB
+ * When we see other devices we know the carrier is ok,
+ * if we are the only device in the beacon group we set the carrier
+ * state to off.
+ * */
+void i1480u_uwb_notifs_cb(void *data, struct uwb_dev *uwb_dev,
+ enum uwb_notifs event)
+{
+ struct i1480u *i1480u = data;
+ struct net_device *net_dev = i1480u->net_dev;
+ struct device *dev = &i1480u->usb_iface->dev;
+ switch (event) {
+ case UWB_NOTIF_BG_JOIN:
+ netif_carrier_on(net_dev);
+ dev_info(dev, "Link is up\n");
+ break;
+ case UWB_NOTIF_BG_LEAVE:
+ netif_carrier_off(net_dev);
+ dev_info(dev, "Link is down\n");
+ break;
+ default:
+ dev_err(dev, "don't know how to handle event %d from uwb\n",
+ event);
+ }
+}
+
+/**
+ * Stop the network queue
+ *
+ * Enable WLP substack to stop network queue. We also set the flow control
+ * threshold at this time to prevent the flow control from restarting the
+ * queue.
+ *
+ * we are loosing the current threshold value here ... FIXME?
+ */
+void i1480u_stop_queue(struct wlp *wlp)
+{
+ struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
+ struct net_device *net_dev = i1480u->net_dev;
+ i1480u->tx_inflight.threshold = 0;
+ netif_stop_queue(net_dev);
+}
+
+/**
+ * Start the network queue
+ *
+ * Enable WLP substack to start network queue. Also re-enable the flow
+ * control to manage the queue again.
+ *
+ * We re-enable the flow control by storing the default threshold in the
+ * flow control threshold. This means that if the user modified the
+ * threshold before the queue was stopped and restarted that information
+ * will be lost. FIXME?
+ */
+void i1480u_start_queue(struct wlp *wlp)
+{
+ struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
+ struct net_device *net_dev = i1480u->net_dev;
+ i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD;
+ netif_start_queue(net_dev);
+}
diff --git a/drivers/uwb/i1480/i1480u-wlp/rx.c b/drivers/uwb/i1480/i1480u-wlp/rx.c
new file mode 100644
index 00000000000..9fc035354a7
--- /dev/null
+++ b/drivers/uwb/i1480/i1480u-wlp/rx.c
@@ -0,0 +1,486 @@
+/*
+ * WUSB Wire Adapter: WLP interface
+ * Driver for the Linux Network stack.
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * i1480u's RX handling is simple. i1480u will send the received
+ * network packets broken up in fragments; 1 to N fragments make a
+ * packet, we assemble them together and deliver the packet with netif_rx().
+ *
+ * Beacuse each USB transfer is a *single* fragment (except when the
+ * transfer contains a first fragment), each URB called thus
+ * back contains one or two fragments. So we queue N URBs, each with its own
+ * fragment buffer. When a URB is done, we process it (adding to the
+ * current skb from the fragment buffer until complete). Once
+ * processed, we requeue the URB. There is always a bunch of URBs
+ * ready to take data, so the intergap should be minimal.
+ *
+ * An URB's transfer buffer is the data field of a socket buffer. This
+ * reduces copying as data can be passed directly to network layer. If a
+ * complete packet or 1st fragment is received the URB's transfer buffer is
+ * taken away from it and used to send data to the network layer. In this
+ * case a new transfer buffer is allocated to the URB before being requeued.
+ * If a "NEXT" or "LAST" fragment is received, the fragment contents is
+ * appended to the RX packet under construction and the transfer buffer
+ * is reused. To be able to use this buffer to assemble complete packets
+ * we set each buffer's size to that of the MAX ethernet packet that can
+ * be received. There is thus room for improvement in memory usage.
+ *
+ * When the max tx fragment size increases, we should be able to read
+ * data into the skbs directly with very simple code.
+ *
+ * ROADMAP:
+ *
+ * ENTRY POINTS:
+ *
+ * i1480u_rx_setup(): setup RX context [from i1480u_open()]
+ *
+ * i1480u_rx_release(): release RX context [from i1480u_stop()]
+ *
+ * i1480u_rx_cb(): called when the RX USB URB receives a
+ * packet. It removes the header and pushes it up
+ * the Linux netdev stack with netif_rx().
+ *
+ * i1480u_rx_buffer()
+ * i1480u_drop() and i1480u_fix()
+ * i1480u_skb_deliver
+ *
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "i1480u-wlp.h"
+
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+
+/**
+ * Setup the RX context
+ *
+ * Each URB is provided with a transfer_buffer that is the data field
+ * of a new socket buffer.
+ */
+int i1480u_rx_setup(struct i1480u *i1480u)
+{
+ int result, cnt;
+ struct device *dev = &i1480u->usb_iface->dev;
+ struct net_device *net_dev = i1480u->net_dev;
+ struct usb_endpoint_descriptor *epd;
+ struct sk_buff *skb;
+
+ /* Alloc RX stuff */
+ i1480u->rx_skb = NULL; /* not in process of receiving packet */
+ result = -ENOMEM;
+ epd = &i1480u->usb_iface->cur_altsetting->endpoint[1].desc;
+ for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
+ struct i1480u_rx_buf *rx_buf = &i1480u->rx_buf[cnt];
+ rx_buf->i1480u = i1480u;
+ skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
+ if (!skb) {
+ dev_err(dev,
+ "RX: cannot allocate RX buffer %d\n", cnt);
+ result = -ENOMEM;
+ goto error;
+ }
+ skb->dev = net_dev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb_reserve(skb, 2);
+ rx_buf->data = skb;
+ rx_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (unlikely(rx_buf->urb == NULL)) {
+ dev_err(dev, "RX: cannot allocate URB %d\n", cnt);
+ result = -ENOMEM;
+ goto error;
+ }
+ usb_fill_bulk_urb(rx_buf->urb, i1480u->usb_dev,
+ usb_rcvbulkpipe(i1480u->usb_dev, epd->bEndpointAddress),
+ rx_buf->data->data, i1480u_MAX_RX_PKT_SIZE - 2,
+ i1480u_rx_cb, rx_buf);
+ result = usb_submit_urb(rx_buf->urb, GFP_NOIO);
+ if (unlikely(result < 0)) {
+ dev_err(dev, "RX: cannot submit URB %d: %d\n",
+ cnt, result);
+ goto error;
+ }
+ }
+ return 0;
+
+error:
+ i1480u_rx_release(i1480u);
+ return result;
+}
+
+
+/** Release resources associated to the rx context */
+void i1480u_rx_release(struct i1480u *i1480u)
+{
+ int cnt;
+ for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
+ if (i1480u->rx_buf[cnt].data)
+ dev_kfree_skb(i1480u->rx_buf[cnt].data);
+ if (i1480u->rx_buf[cnt].urb) {
+ usb_kill_urb(i1480u->rx_buf[cnt].urb);
+ usb_free_urb(i1480u->rx_buf[cnt].urb);
+ }
+ }
+ if (i1480u->rx_skb != NULL)
+ dev_kfree_skb(i1480u->rx_skb);
+}
+
+static
+void i1480u_rx_unlink_urbs(struct i1480u *i1480u)
+{
+ int cnt;
+ for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
+ if (i1480u->rx_buf[cnt].urb)
+ usb_unlink_urb(i1480u->rx_buf[cnt].urb);
+ }
+}
+
+/** Fix an out-of-sequence packet */
+#define i1480u_fix(i1480u, msg...) \
+do { \
+ if (printk_ratelimit()) \
+ dev_err(&i1480u->usb_iface->dev, msg); \
+ dev_kfree_skb_irq(i1480u->rx_skb); \
+ i1480u->rx_skb = NULL; \
+ i1480u->rx_untd_pkt_size = 0; \
+} while (0)
+
+
+/** Drop an out-of-sequence packet */
+#define i1480u_drop(i1480u, msg...) \
+do { \
+ if (printk_ratelimit()) \
+ dev_err(&i1480u->usb_iface->dev, msg); \
+ i1480u->stats.rx_dropped++; \
+} while (0)
+
+
+
+
+/** Finalizes setting up the SKB and delivers it
+ *
+ * We first pass the incoming frame to WLP substack for verification. It
+ * may also be a WLP association frame in which case WLP will take over the
+ * processing. If WLP does not take it over it will still verify it, if the
+ * frame is invalid the skb will be freed by WLP and we will not continue
+ * parsing.
+ * */
+static
+void i1480u_skb_deliver(struct i1480u *i1480u)
+{
+ int should_parse;
+ struct net_device *net_dev = i1480u->net_dev;
+ struct device *dev = &i1480u->usb_iface->dev;
+
+ d_printf(6, dev, "RX delivered pre skb(%p), %u bytes\n",
+ i1480u->rx_skb, i1480u->rx_skb->len);
+ d_dump(7, dev, i1480u->rx_skb->data, i1480u->rx_skb->len);
+ should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb,
+ &i1480u->rx_srcaddr);
+ if (!should_parse)
+ goto out;
+ i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev);
+ d_printf(5, dev, "RX delivered skb(%p), %u bytes\n",
+ i1480u->rx_skb, i1480u->rx_skb->len);
+ d_dump(7, dev, i1480u->rx_skb->data,
+ i1480u->rx_skb->len > 72 ? 72 : i1480u->rx_skb->len);
+ 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 */
+
+ netif_rx(i1480u->rx_skb); /* deliver */
+out:
+ i1480u->rx_skb = NULL;
+ i1480u->rx_untd_pkt_size = 0;
+}
+
+
+/**
+ * Process a buffer of data received from the USB RX endpoint
+ *
+ * First fragment arrives with next or last fragment. All other fragments
+ * arrive alone.
+ *
+ * /me hates long functions.
+ */
+static
+void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf)
+{
+ unsigned pkt_completed = 0; /* !0 when we got all pkt fragments */
+ size_t untd_hdr_size, untd_frg_size;
+ size_t i1480u_hdr_size;
+ struct wlp_rx_hdr *i1480u_hdr = NULL;
+
+ struct i1480u *i1480u = rx_buf->i1480u;
+ struct sk_buff *skb = rx_buf->data;
+ int size_left = rx_buf->urb->actual_length;
+ void *ptr = rx_buf->urb->transfer_buffer; /* also rx_buf->data->data */
+ struct untd_hdr *untd_hdr;
+
+ struct net_device *net_dev = i1480u->net_dev;
+ struct device *dev = &i1480u->usb_iface->dev;
+ struct sk_buff *new_skb;
+
+#if 0
+ dev_fnstart(dev,
+ "(i1480u %p ptr %p size_left %zu)\n", i1480u, ptr, size_left);
+ dev_err(dev, "RX packet, %zu bytes\n", size_left);
+ dump_bytes(dev, ptr, size_left);
+#endif
+ i1480u_hdr_size = sizeof(struct wlp_rx_hdr);
+
+ while (size_left > 0) {
+ if (pkt_completed) {
+ i1480u_drop(i1480u, "RX: fragment follows completed"
+ "packet in same buffer. Dropping\n");
+ break;
+ }
+ untd_hdr = ptr;
+ if (size_left < sizeof(*untd_hdr)) { /* Check the UNTD header */
+ i1480u_drop(i1480u, "RX: short UNTD header! Dropping\n");
+ goto out;
+ }
+ if (unlikely(untd_hdr_rx_tx(untd_hdr) == 0)) { /* Paranoia: TX set? */
+ i1480u_drop(i1480u, "RX: TX bit set! Dropping\n");
+ goto out;
+ }
+ switch (untd_hdr_type(untd_hdr)) { /* Check the UNTD header type */
+ case i1480u_PKT_FRAG_1ST: {
+ struct untd_hdr_1st *untd_hdr_1st = (void *) untd_hdr;
+ dev_dbg(dev, "1st fragment\n");
+ untd_hdr_size = sizeof(struct untd_hdr_1st);
+ if (i1480u->rx_skb != NULL)
+ i1480u_fix(i1480u, "RX: 1st fragment out of "
+ "sequence! Fixing\n");
+ if (size_left < untd_hdr_size + i1480u_hdr_size) {
+ i1480u_drop(i1480u, "RX: short 1st fragment! "
+ "Dropping\n");
+ goto out;
+ }
+ i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len)
+ - i1480u_hdr_size;
+ untd_frg_size = le16_to_cpu(untd_hdr_1st->fragment_len);
+ if (size_left < untd_hdr_size + untd_frg_size) {
+ i1480u_drop(i1480u,
+ "RX: short payload! Dropping\n");
+ goto out;
+ }
+ i1480u->rx_skb = skb;
+ i1480u_hdr = (void *) untd_hdr_1st + untd_hdr_size;
+ i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
+ skb_put(i1480u->rx_skb, untd_hdr_size + untd_frg_size);
+ skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
+ stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
+ stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
+ rx_buf->data = NULL; /* need to create new buffer */
+ break;
+ }
+ case i1480u_PKT_FRAG_NXT: {
+ dev_dbg(dev, "nxt fragment\n");
+ untd_hdr_size = sizeof(struct untd_hdr_rst);
+ if (i1480u->rx_skb == NULL) {
+ i1480u_drop(i1480u, "RX: next fragment out of "
+ "sequence! Dropping\n");
+ goto out;
+ }
+ if (size_left < untd_hdr_size) {
+ i1480u_drop(i1480u, "RX: short NXT fragment! "
+ "Dropping\n");
+ goto out;
+ }
+ untd_frg_size = le16_to_cpu(untd_hdr->len);
+ if (size_left < untd_hdr_size + untd_frg_size) {
+ i1480u_drop(i1480u,
+ "RX: short payload! Dropping\n");
+ goto out;
+ }
+ memmove(skb_put(i1480u->rx_skb, untd_frg_size),
+ ptr + untd_hdr_size, untd_frg_size);
+ break;
+ }
+ case i1480u_PKT_FRAG_LST: {
+ dev_dbg(dev, "Lst fragment\n");
+ untd_hdr_size = sizeof(struct untd_hdr_rst);
+ if (i1480u->rx_skb == NULL) {
+ i1480u_drop(i1480u, "RX: last fragment out of "
+ "sequence! Dropping\n");
+ goto out;
+ }
+ if (size_left < untd_hdr_size) {
+ i1480u_drop(i1480u, "RX: short LST fragment! "
+ "Dropping\n");
+ goto out;
+ }
+ untd_frg_size = le16_to_cpu(untd_hdr->len);
+ if (size_left < untd_frg_size + untd_hdr_size) {
+ i1480u_drop(i1480u,
+ "RX: short payload! Dropping\n");
+ goto out;
+ }
+ memmove(skb_put(i1480u->rx_skb, untd_frg_size),
+ ptr + untd_hdr_size, untd_frg_size);
+ pkt_completed = 1;
+ break;
+ }
+ case i1480u_PKT_FRAG_CMP: {
+ dev_dbg(dev, "cmp fragment\n");
+ untd_hdr_size = sizeof(struct untd_hdr_cmp);
+ if (i1480u->rx_skb != NULL)
+ i1480u_fix(i1480u, "RX: fix out-of-sequence CMP"
+ " fragment!\n");
+ if (size_left < untd_hdr_size + i1480u_hdr_size) {
+ i1480u_drop(i1480u, "RX: short CMP fragment! "
+ "Dropping\n");
+ goto out;
+ }
+ i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len);
+ untd_frg_size = i1480u->rx_untd_pkt_size;
+ if (size_left < i1480u->rx_untd_pkt_size + untd_hdr_size) {
+ i1480u_drop(i1480u,
+ "RX: short payload! Dropping\n");
+ goto out;
+ }
+ i1480u->rx_skb = skb;
+ i1480u_hdr = (void *) untd_hdr + untd_hdr_size;
+ i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
+ stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
+ stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
+ skb_put(i1480u->rx_skb, untd_hdr_size + i1480u->rx_untd_pkt_size);
+ skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
+ rx_buf->data = NULL; /* for hand off skb to network stack */
+ pkt_completed = 1;
+ i1480u->rx_untd_pkt_size -= i1480u_hdr_size; /* accurate stat */
+ break;
+ }
+ default:
+ i1480u_drop(i1480u, "RX: unknown packet type %u! "
+ "Dropping\n", untd_hdr_type(untd_hdr));
+ goto out;
+ }
+ size_left -= untd_hdr_size + untd_frg_size;
+ if (size_left > 0)
+ ptr += untd_hdr_size + untd_frg_size;
+ }
+ if (pkt_completed)
+ i1480u_skb_deliver(i1480u);
+out:
+ /* recreate needed RX buffers*/
+ if (rx_buf->data == NULL) {
+ /* buffer is being used to receive packet, create new */
+ new_skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
+ if (!new_skb) {
+ if (printk_ratelimit())
+ dev_err(dev,
+ "RX: cannot allocate RX buffer\n");
+ } else {
+ new_skb->dev = net_dev;
+ new_skb->ip_summed = CHECKSUM_NONE;
+ skb_reserve(new_skb, 2);
+ rx_buf->data = new_skb;
+ }
+ }
+ return;
+}
+
+
+/**
+ * Called when an RX URB has finished receiving or has found some kind
+ * of error condition.
+ *
+ * LIMITATIONS:
+ *
+ * - We read USB-transfers, each transfer contains a SINGLE fragment
+ * (can contain a complete packet, or a 1st, next, or last fragment
+ * of a packet).
+ * Looks like a transfer can contain more than one fragment (07/18/06)
+ *
+ * - Each transfer buffer is the size of the maximum packet size (minus
+ * headroom), i1480u_MAX_PKT_SIZE - 2
+ *
+ * - We always read the full USB-transfer, no partials.
+ *
+ * - Each transfer is read directly into a skb. This skb will be used to
+ * send data to the upper layers if it is the first fragment or a complete
+ * packet. In the other cases the data will be copied from the skb to
+ * another skb that is being prepared for the upper layers from a prev
+ * first fragment.
+ *
+ * It is simply too much of a pain. Gosh, there should be a unified
+ * SG infrastructure for *everything* [so that I could declare a SG
+ * buffer, pass it to USB for receiving, append some space to it if
+ * I wish, receive more until I have the whole chunk, adapt
+ * pointers on each fragment to remove hardware headers and then
+ * attach that to an skbuff and netif_rx()].
+ */
+void i1480u_rx_cb(struct urb *urb)
+{
+ int result;
+ int do_parse_buffer = 1;
+ struct i1480u_rx_buf *rx_buf = urb->context;
+ struct i1480u *i1480u = rx_buf->i1480u;
+ struct device *dev = &i1480u->usb_iface->dev;
+ unsigned long flags;
+ u8 rx_buf_idx = rx_buf - i1480u->rx_buf;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ECONNRESET: /* Not an error, but a controlled situation; */
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ case -ESHUTDOWN: /* going away! */
+ dev_err(dev, "RX URB[%u]: goind down %d\n",
+ rx_buf_idx, urb->status);
+ goto error;
+ default:
+ dev_err(dev, "RX URB[%u]: unknown status %d\n",
+ rx_buf_idx, urb->status);
+ if (edc_inc(&i1480u->rx_errors, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "RX: max acceptable errors exceeded,"
+ " resetting device.\n");
+ i1480u_rx_unlink_urbs(i1480u);
+ wlp_reset_all(&i1480u->wlp);
+ goto error;
+ }
+ do_parse_buffer = 0;
+ break;
+ }
+ spin_lock_irqsave(&i1480u->lock, flags);
+ /* chew the data fragments, extract network packets */
+ if (do_parse_buffer) {
+ i1480u_rx_buffer(rx_buf);
+ if (rx_buf->data) {
+ rx_buf->urb->transfer_buffer = rx_buf->data->data;
+ result = usb_submit_urb(rx_buf->urb, GFP_ATOMIC);
+ if (result < 0) {
+ dev_err(dev, "RX URB[%u]: cannot submit %d\n",
+ rx_buf_idx, result);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&i1480u->lock, flags);
+error:
+ return;
+}
+
diff --git a/drivers/uwb/i1480/i1480u-wlp/sysfs.c b/drivers/uwb/i1480/i1480u-wlp/sysfs.c
new file mode 100644
index 00000000000..a1d8ca6ac93
--- /dev/null
+++ b/drivers/uwb/i1480/i1480u-wlp/sysfs.c
@@ -0,0 +1,408 @@
+/*
+ * WUSB Wire Adapter: WLP interface
+ * Sysfs interfaces
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/uwb/debug.h>
+#include <linux/device.h>
+#include "i1480u-wlp.h"
+
+
+/**
+ *
+ * @dev: Class device from the net_device; assumed refcnted.
+ *
+ * Yes, I don't lock--we assume it is refcounted and I am getting a
+ * single byte value that is kind of atomic to read.
+ */
+ssize_t uwb_phy_rate_show(const struct wlp_options *options, char *buf)
+{
+ return sprintf(buf, "%u\n",
+ wlp_tx_hdr_phy_rate(&options->def_tx_hdr));
+}
+EXPORT_SYMBOL_GPL(uwb_phy_rate_show);
+
+
+ssize_t uwb_phy_rate_store(struct wlp_options *options,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ unsigned rate;
+
+ result = sscanf(buf, "%u\n", &rate);
+ if (result != 1) {
+ result = -EINVAL;
+ goto out;
+ }
+ result = -EINVAL;
+ if (rate >= UWB_PHY_RATE_INVALID)
+ goto out;
+ wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, rate);
+ result = 0;
+out:
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(uwb_phy_rate_store);
+
+
+ssize_t uwb_rts_cts_show(const struct wlp_options *options, char *buf)
+{
+ return sprintf(buf, "%u\n",
+ wlp_tx_hdr_rts_cts(&options->def_tx_hdr));
+}
+EXPORT_SYMBOL_GPL(uwb_rts_cts_show);
+
+
+ssize_t uwb_rts_cts_store(struct wlp_options *options,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ unsigned value;
+
+ result = sscanf(buf, "%u\n", &value);
+ if (result != 1) {
+ result = -EINVAL;
+ goto out;
+ }
+ result = -EINVAL;
+ wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, !!value);
+ result = 0;
+out:
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(uwb_rts_cts_store);
+
+
+ssize_t uwb_ack_policy_show(const struct wlp_options *options, char *buf)
+{
+ return sprintf(buf, "%u\n",
+ wlp_tx_hdr_ack_policy(&options->def_tx_hdr));
+}
+EXPORT_SYMBOL_GPL(uwb_ack_policy_show);
+
+
+ssize_t uwb_ack_policy_store(struct wlp_options *options,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ unsigned value;
+
+ result = sscanf(buf, "%u\n", &value);
+ if (result != 1 || value > UWB_ACK_B_REQ) {
+ result = -EINVAL;
+ goto out;
+ }
+ wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, value);
+ result = 0;
+out:
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(uwb_ack_policy_store);
+
+
+/**
+ * Show the PCA base priority.
+ *
+ * We can access without locking, as the value is (for now) orthogonal
+ * to other values.
+ */
+ssize_t uwb_pca_base_priority_show(const struct wlp_options *options,
+ char *buf)
+{
+ return sprintf(buf, "%u\n",
+ options->pca_base_priority);
+}
+EXPORT_SYMBOL_GPL(uwb_pca_base_priority_show);
+
+
+/**
+ * Set the PCA base priority.
+ *
+ * We can access without locking, as the value is (for now) orthogonal
+ * to other values.
+ */
+ssize_t uwb_pca_base_priority_store(struct wlp_options *options,
+ const char *buf, size_t size)
+{
+ ssize_t result = -EINVAL;
+ u8 pca_base_priority;
+
+ result = sscanf(buf, "%hhu\n", &pca_base_priority);
+ if (result != 1) {
+ result = -EINVAL;
+ goto out;
+ }
+ result = -EINVAL;
+ if (pca_base_priority >= 8)
+ goto out;
+ options->pca_base_priority = pca_base_priority;
+ /* Update TX header if we are currently using PCA. */
+ if (result >= 0 && (wlp_tx_hdr_delivery_id_type(&options->def_tx_hdr) & WLP_DRP) == 0)
+ wlp_tx_hdr_set_delivery_id_type(&options->def_tx_hdr, options->pca_base_priority);
+ result = 0;
+out:
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(uwb_pca_base_priority_store);
+
+/**
+ * Show current inflight values
+ *
+ * Will print the current MAX and THRESHOLD values for the basic flow
+ * control. In addition it will report how many times the TX queue needed
+ * to be restarted since the last time this query was made.
+ */
+static ssize_t wlp_tx_inflight_show(struct i1480u_tx_inflight *inflight,
+ char *buf)
+{
+ ssize_t result;
+ unsigned long sec_elapsed = (jiffies - inflight->restart_ts)/HZ;
+ unsigned long restart_count = atomic_read(&inflight->restart_count);
+
+ result = scnprintf(buf, PAGE_SIZE, "%lu %lu %d %lu %lu %lu\n"
+ "#read: threshold max inflight_count restarts "
+ "seconds restarts/sec\n"
+ "#write: threshold max\n",
+ inflight->threshold, inflight->max,
+ atomic_read(&inflight->count),
+ restart_count, sec_elapsed,
+ sec_elapsed == 0 ? 0 : restart_count/sec_elapsed);
+ inflight->restart_ts = jiffies;
+ atomic_set(&inflight->restart_count, 0);
+ return result;
+}
+
+static
+ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight,
+ const char *buf, size_t size)
+{
+ unsigned long in_threshold, in_max;
+ ssize_t result;
+ result = sscanf(buf, "%lu %lu", &in_threshold, &in_max);
+ if (result != 2)
+ return -EINVAL;
+ if (in_max <= in_threshold)
+ return -EINVAL;
+ inflight->max = in_max;
+ inflight->threshold = in_threshold;
+ return size;
+}
+/*
+ * Glue (or function adaptors) for accesing info on sysfs
+ *
+ * [we need this indirection because the PCI driver does almost the
+ * same]
+ *
+ * Linux 2.6.21 changed how 'struct netdevice' does attributes (from
+ * having a 'struct class_dev' to having a 'struct device'). That is
+ * quite of a pain.
+ *
+ * So we try to abstract that here. i1480u_SHOW() and i1480u_STORE()
+ * create adaptors for extracting the 'struct i1480u' from a 'struct
+ * dev' and calling a function for doing a sysfs operation (as we have
+ * them factorized already). i1480u_ATTR creates the attribute file
+ * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a
+ * class_device_attr_NAME or device_attr_NAME (for group registration).
+ */
+#include <linux/version.h>
+
+#define i1480u_SHOW(name, fn, param) \
+static ssize_t i1480u_show_##name(struct device *dev, \
+ struct device_attribute *attr,\
+ char *buf) \
+{ \
+ struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \
+ return fn(&i1480u->param, buf); \
+}
+
+#define i1480u_STORE(name, fn, param) \
+static ssize_t i1480u_store_##name(struct device *dev, \
+ struct device_attribute *attr,\
+ const char *buf, size_t size)\
+{ \
+ struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \
+ return fn(&i1480u->param, buf, size); \
+}
+
+#define i1480u_ATTR(name, perm) static DEVICE_ATTR(name, perm, \
+ i1480u_show_##name,\
+ i1480u_store_##name)
+
+#define i1480u_ATTR_SHOW(name) static DEVICE_ATTR(name, \
+ S_IRUGO, \
+ i1480u_show_##name, NULL)
+
+#define i1480u_ATTR_NAME(a) (dev_attr_##a)
+
+
+/*
+ * Sysfs adaptors
+ */
+i1480u_SHOW(uwb_phy_rate, uwb_phy_rate_show, options);
+i1480u_STORE(uwb_phy_rate, uwb_phy_rate_store, options);
+i1480u_ATTR(uwb_phy_rate, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(uwb_rts_cts, uwb_rts_cts_show, options);
+i1480u_STORE(uwb_rts_cts, uwb_rts_cts_store, options);
+i1480u_ATTR(uwb_rts_cts, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(uwb_ack_policy, uwb_ack_policy_show, options);
+i1480u_STORE(uwb_ack_policy, uwb_ack_policy_store, options);
+i1480u_ATTR(uwb_ack_policy, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(uwb_pca_base_priority, uwb_pca_base_priority_show, options);
+i1480u_STORE(uwb_pca_base_priority, uwb_pca_base_priority_store, options);
+i1480u_ATTR(uwb_pca_base_priority, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_eda, wlp_eda_show, wlp);
+i1480u_STORE(wlp_eda, wlp_eda_store, wlp);
+i1480u_ATTR(wlp_eda, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_uuid, wlp_uuid_show, wlp);
+i1480u_STORE(wlp_uuid, wlp_uuid_store, wlp);
+i1480u_ATTR(wlp_uuid, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_dev_name, wlp_dev_name_show, wlp);
+i1480u_STORE(wlp_dev_name, wlp_dev_name_store, wlp);
+i1480u_ATTR(wlp_dev_name, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_dev_manufacturer, wlp_dev_manufacturer_show, wlp);
+i1480u_STORE(wlp_dev_manufacturer, wlp_dev_manufacturer_store, wlp);
+i1480u_ATTR(wlp_dev_manufacturer, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_dev_model_name, wlp_dev_model_name_show, wlp);
+i1480u_STORE(wlp_dev_model_name, wlp_dev_model_name_store, wlp);
+i1480u_ATTR(wlp_dev_model_name, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_dev_model_nr, wlp_dev_model_nr_show, wlp);
+i1480u_STORE(wlp_dev_model_nr, wlp_dev_model_nr_store, wlp);
+i1480u_ATTR(wlp_dev_model_nr, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_dev_serial, wlp_dev_serial_show, wlp);
+i1480u_STORE(wlp_dev_serial, wlp_dev_serial_store, wlp);
+i1480u_ATTR(wlp_dev_serial, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_dev_prim_category, wlp_dev_prim_category_show, wlp);
+i1480u_STORE(wlp_dev_prim_category, wlp_dev_prim_category_store, wlp);
+i1480u_ATTR(wlp_dev_prim_category, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_dev_prim_OUI, wlp_dev_prim_OUI_show, wlp);
+i1480u_STORE(wlp_dev_prim_OUI, wlp_dev_prim_OUI_store, wlp);
+i1480u_ATTR(wlp_dev_prim_OUI, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_show, wlp);
+i1480u_STORE(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_store, wlp);
+i1480u_ATTR(wlp_dev_prim_OUI_sub, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_dev_prim_subcat, wlp_dev_prim_subcat_show, wlp);
+i1480u_STORE(wlp_dev_prim_subcat, wlp_dev_prim_subcat_store, wlp);
+i1480u_ATTR(wlp_dev_prim_subcat, S_IRUGO | S_IWUSR);
+
+i1480u_SHOW(wlp_neighborhood, wlp_neighborhood_show, wlp);
+i1480u_ATTR_SHOW(wlp_neighborhood);
+
+i1480u_SHOW(wss_activate, wlp_wss_activate_show, wlp.wss);
+i1480u_STORE(wss_activate, wlp_wss_activate_store, wlp.wss);
+i1480u_ATTR(wss_activate, S_IRUGO | S_IWUSR);
+
+/*
+ * Show the (min, max, avg) Line Quality Estimate (LQE, in dB) as over
+ * the last 256 received WLP frames (ECMA-368 13.3).
+ *
+ * [the -7dB that have to be substracted from the LQI to make the LQE
+ * are already taken into account].
+ */
+i1480u_SHOW(wlp_lqe, stats_show, lqe_stats);
+i1480u_STORE(wlp_lqe, stats_store, lqe_stats);
+i1480u_ATTR(wlp_lqe, S_IRUGO | S_IWUSR);
+
+/*
+ * Show the Receive Signal Strength Indicator averaged over all the
+ * received WLP frames (ECMA-368 13.3). Still is not clear what
+ * this value is, but is kind of a percentage of the signal strength
+ * at the antenna.
+ */
+i1480u_SHOW(wlp_rssi, stats_show, rssi_stats);
+i1480u_STORE(wlp_rssi, stats_store, rssi_stats);
+i1480u_ATTR(wlp_rssi, S_IRUGO | S_IWUSR);
+
+/**
+ * We maintain a basic flow control counter. "count" how many TX URBs are
+ * outstanding. Only allow "max"
+ * TX URBs to be outstanding. If this value is reached the queue will be
+ * stopped. The queue will be restarted when there are
+ * "threshold" URBs outstanding.
+ */
+i1480u_SHOW(wlp_tx_inflight, wlp_tx_inflight_show, tx_inflight);
+i1480u_STORE(wlp_tx_inflight, wlp_tx_inflight_store, tx_inflight);
+i1480u_ATTR(wlp_tx_inflight, S_IRUGO | S_IWUSR);
+
+static struct attribute *i1480u_attrs[] = {
+ &i1480u_ATTR_NAME(uwb_phy_rate).attr,
+ &i1480u_ATTR_NAME(uwb_rts_cts).attr,
+ &i1480u_ATTR_NAME(uwb_ack_policy).attr,
+ &i1480u_ATTR_NAME(uwb_pca_base_priority).attr,
+ &i1480u_ATTR_NAME(wlp_lqe).attr,
+ &i1480u_ATTR_NAME(wlp_rssi).attr,
+ &i1480u_ATTR_NAME(wlp_eda).attr,
+ &i1480u_ATTR_NAME(wlp_uuid).attr,
+ &i1480u_ATTR_NAME(wlp_dev_name).attr,
+ &i1480u_ATTR_NAME(wlp_dev_manufacturer).attr,
+ &i1480u_ATTR_NAME(wlp_dev_model_name).attr,
+ &i1480u_ATTR_NAME(wlp_dev_model_nr).attr,
+ &i1480u_ATTR_NAME(wlp_dev_serial).attr,
+ &i1480u_ATTR_NAME(wlp_dev_prim_category).attr,
+ &i1480u_ATTR_NAME(wlp_dev_prim_OUI).attr,
+ &i1480u_ATTR_NAME(wlp_dev_prim_OUI_sub).attr,
+ &i1480u_ATTR_NAME(wlp_dev_prim_subcat).attr,
+ &i1480u_ATTR_NAME(wlp_neighborhood).attr,
+ &i1480u_ATTR_NAME(wss_activate).attr,
+ &i1480u_ATTR_NAME(wlp_tx_inflight).attr,
+ NULL,
+};
+
+static struct attribute_group i1480u_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = i1480u_attrs,
+};
+
+int i1480u_sysfs_setup(struct i1480u *i1480u)
+{
+ int result;
+ struct device *dev = &i1480u->usb_iface->dev;
+ result = sysfs_create_group(&i1480u->net_dev->dev.kobj,
+ &i1480u_attr_group);
+ if (result < 0)
+ dev_err(dev, "cannot initialize sysfs attributes: %d\n",
+ result);
+ return result;
+}
+
+
+void i1480u_sysfs_release(struct i1480u *i1480u)
+{
+ sysfs_remove_group(&i1480u->net_dev->dev.kobj,
+ &i1480u_attr_group);
+}
diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c
new file mode 100644
index 00000000000..3426bfb6824
--- /dev/null
+++ b/drivers/uwb/i1480/i1480u-wlp/tx.c
@@ -0,0 +1,632 @@
+/*
+ * WUSB Wire Adapter: WLP interface
+ * Deal with TX (massaging data to transmit, handling it)
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * Transmission engine. Get an skb, create from that a WLP transmit
+ * context, add a WLP TX header (which we keep prefilled in the
+ * device's instance), fill out the target-specific fields and
+ * fire it.
+ *
+ * ROADMAP:
+ *
+ * Entry points:
+ *
+ * i1480u_tx_release(): called by i1480u_disconnect() to release
+ * pending tx contexts.
+ *
+ * i1480u_tx_cb(): callback for TX contexts (USB URBs)
+ * i1480u_tx_destroy():
+ *
+ * i1480u_tx_timeout(): called for timeout handling from the
+ * network stack.
+ *
+ * i1480u_hard_start_xmit(): called for transmitting an skb from
+ * the network stack. Will interact with WLP
+ * substack to verify and prepare frame.
+ * i1480u_xmit_frame(): actual transmission on hardware
+ *
+ * i1480u_tx_create() Creates TX context
+ * i1480u_tx_create_1() For packets in 1 fragment
+ * i1480u_tx_create_n() For packets in >1 fragments
+ *
+ * TODO:
+ *
+ * - FIXME: rewrite using usb_sg_*(), add asynch support to
+ * usb_sg_*(). It might not make too much sense as most of
+ * the times the MTU will be smaller than one page...
+ */
+
+#include "i1480u-wlp.h"
+#define D_LOCAL 5
+#include <linux/uwb/debug.h>
+
+enum {
+ /* This is only for Next and Last TX packets */
+ i1480u_MAX_PL_SIZE = i1480u_MAX_FRG_SIZE
+ - sizeof(struct untd_hdr_rst),
+};
+
+/** Free resources allocated to a i1480u tx context. */
+static
+void i1480u_tx_free(struct i1480u_tx *wtx)
+{
+ kfree(wtx->buf);
+ if (wtx->skb)
+ dev_kfree_skb_irq(wtx->skb);
+ usb_free_urb(wtx->urb);
+ kfree(wtx);
+}
+
+static
+void i1480u_tx_destroy(struct i1480u *i1480u, struct i1480u_tx *wtx)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&i1480u->tx_list_lock, flags); /* not active any more */
+ list_del(&wtx->list_node);
+ i1480u_tx_free(wtx);
+ spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
+}
+
+static
+void i1480u_tx_unlink_urbs(struct i1480u *i1480u)
+{
+ unsigned long flags;
+ struct i1480u_tx *wtx, *next;
+
+ spin_lock_irqsave(&i1480u->tx_list_lock, flags);
+ list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) {
+ usb_unlink_urb(wtx->urb);
+ }
+ spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
+}
+
+
+/**
+ * Callback for a completed tx USB URB.
+ *
+ * TODO:
+ *
+ * - FIXME: recover errors more gracefully
+ * - FIXME: handle NAKs (I dont think they come here) for flow ctl
+ */
+static
+void i1480u_tx_cb(struct urb *urb)
+{
+ struct i1480u_tx *wtx = urb->context;
+ struct i1480u *i1480u = wtx->i1480u;
+ struct net_device *net_dev = i1480u->net_dev;
+ struct device *dev = &i1480u->usb_iface->dev;
+ unsigned long flags;
+
+ switch (urb->status) {
+ case 0:
+ spin_lock_irqsave(&i1480u->lock, flags);
+ i1480u->stats.tx_packets++;
+ i1480u->stats.tx_bytes += urb->actual_length;
+ spin_unlock_irqrestore(&i1480u->lock, flags);
+ break;
+ case -ECONNRESET: /* Not an error, but a controlled situation; */
+ case -ENOENT: /* (we killed the URB)...so, no broadcast */
+ dev_dbg(dev, "notif endp: reset/noent %d\n", urb->status);
+ netif_stop_queue(net_dev);
+ break;
+ case -ESHUTDOWN: /* going away! */
+ dev_dbg(dev, "notif endp: down %d\n", urb->status);
+ netif_stop_queue(net_dev);
+ break;
+ default:
+ dev_err(dev, "TX: unknown URB status %d\n", urb->status);
+ if (edc_inc(&i1480u->tx_errors, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "TX: max acceptable errors exceeded."
+ "Reset device.\n");
+ netif_stop_queue(net_dev);
+ i1480u_tx_unlink_urbs(i1480u);
+ wlp_reset_all(&i1480u->wlp);
+ }
+ break;
+ }
+ i1480u_tx_destroy(i1480u, wtx);
+ if (atomic_dec_return(&i1480u->tx_inflight.count)
+ <= i1480u->tx_inflight.threshold
+ && netif_queue_stopped(net_dev)
+ && i1480u->tx_inflight.threshold != 0) {
+ if (d_test(2) && printk_ratelimit())
+ d_printf(2, dev, "Restart queue. \n");
+ netif_start_queue(net_dev);
+ atomic_inc(&i1480u->tx_inflight.restart_count);
+ }
+ return;
+}
+
+
+/**
+ * Given a buffer that doesn't fit in a single fragment, create an
+ * scatter/gather structure for delivery to the USB pipe.
+ *
+ * Implements functionality of i1480u_tx_create().
+ *
+ * @wtx: tx descriptor
+ * @skb: skb to send
+ * @gfp_mask: gfp allocation mask
+ * @returns: Pointer to @wtx if ok, NULL on error.
+ *
+ * Sorry, TOO LONG a function, but breaking it up is kind of hard
+ *
+ * This will break the buffer in chunks smaller than
+ * i1480u_MAX_FRG_SIZE (including the header) and add proper headers
+ * to each:
+ *
+ * 1st header \
+ * i1480 tx header | fragment 1
+ * fragment data /
+ * nxt header \ fragment 2
+ * fragment data /
+ * ..
+ * ..
+ * last header \ fragment 3
+ * last fragment data /
+ *
+ * This does not fill the i1480 TX header, it is left up to the
+ * caller to do that; you can get it from @wtx->wlp_tx_hdr.
+ *
+ * This function consumes the skb unless there is an error.
+ */
+static
+int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb,
+ gfp_t gfp_mask)
+{
+ int result;
+ void *pl;
+ size_t pl_size;
+
+ void *pl_itr, *buf_itr;
+ size_t pl_size_left, frgs, pl_size_1st, frg_pl_size = 0;
+ struct untd_hdr_1st *untd_hdr_1st;
+ struct wlp_tx_hdr *wlp_tx_hdr;
+ struct untd_hdr_rst *untd_hdr_rst;
+
+ wtx->skb = NULL;
+ pl = skb->data;
+ pl_itr = pl;
+ pl_size = skb->len;
+ pl_size_left = pl_size; /* payload size */
+ /* First fragment; fits as much as i1480u_MAX_FRG_SIZE minus
+ * the headers */
+ pl_size_1st = i1480u_MAX_FRG_SIZE
+ - sizeof(struct untd_hdr_1st) - sizeof(struct wlp_tx_hdr);
+ BUG_ON(pl_size_1st > pl_size);
+ pl_size_left -= pl_size_1st;
+ /* The rest have an smaller header (no i1480 TX header). We
+ * need to break up the payload in blocks smaller than
+ * i1480u_MAX_PL_SIZE (payload excluding header). */
+ frgs = (pl_size_left + i1480u_MAX_PL_SIZE - 1) / i1480u_MAX_PL_SIZE;
+ /* Allocate space for the new buffer. In this new buffer we'll
+ * place the headers followed by the data fragment, headers,
+ * data fragments, etc..
+ */
+ result = -ENOMEM;
+ wtx->buf_size = sizeof(*untd_hdr_1st)
+ + sizeof(*wlp_tx_hdr)
+ + frgs * sizeof(*untd_hdr_rst)
+ + pl_size;
+ wtx->buf = kmalloc(wtx->buf_size, gfp_mask);
+ if (wtx->buf == NULL)
+ goto error_buf_alloc;
+
+ buf_itr = wtx->buf; /* We got the space, let's fill it up */
+ /* Fill 1st fragment */
+ untd_hdr_1st = buf_itr;
+ buf_itr += sizeof(*untd_hdr_1st);
+ untd_hdr_set_type(&untd_hdr_1st->hdr, i1480u_PKT_FRAG_1ST);
+ untd_hdr_set_rx_tx(&untd_hdr_1st->hdr, 0);
+ untd_hdr_1st->hdr.len = cpu_to_le16(pl_size + sizeof(*wlp_tx_hdr));
+ untd_hdr_1st->fragment_len =
+ cpu_to_le16(pl_size_1st + sizeof(*wlp_tx_hdr));
+ memset(untd_hdr_1st->padding, 0, sizeof(untd_hdr_1st->padding));
+ /* Set up i1480 header info */
+ wlp_tx_hdr = wtx->wlp_tx_hdr = buf_itr;
+ buf_itr += sizeof(*wlp_tx_hdr);
+ /* Copy the first fragment */
+ memcpy(buf_itr, pl_itr, pl_size_1st);
+ pl_itr += pl_size_1st;
+ buf_itr += pl_size_1st;
+
+ /* Now do each remaining fragment */
+ result = -EINVAL;
+ while (pl_size_left > 0) {
+ d_printf(5, NULL, "ITR HDR: pl_size_left %zu buf_itr %zu\n",
+ pl_size_left, buf_itr - wtx->buf);
+ if (buf_itr + sizeof(*untd_hdr_rst) - wtx->buf
+ > wtx->buf_size) {
+ printk(KERN_ERR "BUG: no space for header\n");
+ goto error_bug;
+ }
+ d_printf(5, NULL, "ITR HDR 2: pl_size_left %zu buf_itr %zu\n",
+ pl_size_left, buf_itr - wtx->buf);
+ untd_hdr_rst = buf_itr;
+ buf_itr += sizeof(*untd_hdr_rst);
+ if (pl_size_left > i1480u_MAX_PL_SIZE) {
+ frg_pl_size = i1480u_MAX_PL_SIZE;
+ untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_NXT);
+ } else {
+ frg_pl_size = pl_size_left;
+ untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_LST);
+ }
+ d_printf(5, NULL,
+ "ITR PL: pl_size_left %zu buf_itr %zu frg_pl_size %zu\n",
+ pl_size_left, buf_itr - wtx->buf, frg_pl_size);
+ untd_hdr_set_rx_tx(&untd_hdr_rst->hdr, 0);
+ untd_hdr_rst->hdr.len = cpu_to_le16(frg_pl_size);
+ untd_hdr_rst->padding = 0;
+ if (buf_itr + frg_pl_size - wtx->buf
+ > wtx->buf_size) {
+ printk(KERN_ERR "BUG: no space for payload\n");
+ goto error_bug;
+ }
+ memcpy(buf_itr, pl_itr, frg_pl_size);
+ buf_itr += frg_pl_size;
+ pl_itr += frg_pl_size;
+ pl_size_left -= frg_pl_size;
+ d_printf(5, NULL,
+ "ITR PL 2: pl_size_left %zu buf_itr %zu frg_pl_size %zu\n",
+ pl_size_left, buf_itr - wtx->buf, frg_pl_size);
+ }
+ dev_kfree_skb_irq(skb);
+ return 0;
+
+error_bug:
+ printk(KERN_ERR
+ "BUG: skb %u bytes\n"
+ "BUG: frg_pl_size %zd i1480u_MAX_FRG_SIZE %u\n"
+ "BUG: buf_itr %zu buf_size %zu pl_size_left %zu\n",
+ skb->len,
+ frg_pl_size, i1480u_MAX_FRG_SIZE,
+ buf_itr - wtx->buf, wtx->buf_size, pl_size_left);
+
+ kfree(wtx->buf);
+error_buf_alloc:
+ return result;
+}
+
+
+/**
+ * Given a buffer that fits in a single fragment, fill out a @wtx
+ * struct for transmitting it down the USB pipe.
+ *
+ * Uses the fact that we have space reserved in front of the skbuff
+ * for hardware headers :]
+ *
+ * This does not fill the i1480 TX header, it is left up to the
+ * caller to do that; you can get it from @wtx->wlp_tx_hdr.
+ *
+ * @pl: pointer to payload data
+ * @pl_size: size of the payuload
+ *
+ * This function does not consume the @skb.
+ */
+static
+int i1480u_tx_create_1(struct i1480u_tx *wtx, struct sk_buff *skb,
+ gfp_t gfp_mask)
+{
+ struct untd_hdr_cmp *untd_hdr_cmp;
+ struct wlp_tx_hdr *wlp_tx_hdr;
+
+ wtx->buf = NULL;
+ wtx->skb = skb;
+ BUG_ON(skb_headroom(skb) < sizeof(*wlp_tx_hdr));
+ wlp_tx_hdr = (void *) __skb_push(skb, sizeof(*wlp_tx_hdr));
+ wtx->wlp_tx_hdr = wlp_tx_hdr;
+ BUG_ON(skb_headroom(skb) < sizeof(*untd_hdr_cmp));
+ untd_hdr_cmp = (void *) __skb_push(skb, sizeof(*untd_hdr_cmp));
+
+ untd_hdr_set_type(&untd_hdr_cmp->hdr, i1480u_PKT_FRAG_CMP);
+ untd_hdr_set_rx_tx(&untd_hdr_cmp->hdr, 0);
+ untd_hdr_cmp->hdr.len = cpu_to_le16(skb->len - sizeof(*untd_hdr_cmp));
+ untd_hdr_cmp->padding = 0;
+ return 0;
+}
+
+
+/**
+ * Given a skb to transmit, massage it to become palatable for the TX pipe
+ *
+ * This will break the buffer in chunks smaller than
+ * i1480u_MAX_FRG_SIZE and add proper headers to each.
+ *
+ * 1st header \
+ * i1480 tx header | fragment 1
+ * fragment data /
+ * nxt header \ fragment 2
+ * fragment data /
+ * ..
+ * ..
+ * last header \ fragment 3
+ * last fragment data /
+ *
+ * Each fragment will be always smaller or equal to i1480u_MAX_FRG_SIZE.
+ *
+ * If the first fragment is smaller than i1480u_MAX_FRG_SIZE, then the
+ * following is composed:
+ *
+ * complete header \
+ * i1480 tx header | single fragment
+ * packet data /
+ *
+ * We were going to use s/g support, but because the interface is
+ * synch and at the end there is plenty of overhead to do it, it
+ * didn't seem that worth for data that is going to be smaller than
+ * one page.
+ */
+static
+struct i1480u_tx *i1480u_tx_create(struct i1480u *i1480u,
+ struct sk_buff *skb, gfp_t gfp_mask)
+{
+ int result;
+ struct usb_endpoint_descriptor *epd;
+ int usb_pipe;
+ unsigned long flags;
+
+ struct i1480u_tx *wtx;
+ const size_t pl_max_size =
+ i1480u_MAX_FRG_SIZE - sizeof(struct untd_hdr_cmp)
+ - sizeof(struct wlp_tx_hdr);
+
+ wtx = kmalloc(sizeof(*wtx), gfp_mask);
+ if (wtx == NULL)
+ goto error_wtx_alloc;
+ wtx->urb = usb_alloc_urb(0, gfp_mask);
+ if (wtx->urb == NULL)
+ goto error_urb_alloc;
+ epd = &i1480u->usb_iface->cur_altsetting->endpoint[2].desc;
+ usb_pipe = usb_sndbulkpipe(i1480u->usb_dev, epd->bEndpointAddress);
+ /* Fits in a single complete packet or need to split? */
+ if (skb->len > pl_max_size) {
+ result = i1480u_tx_create_n(wtx, skb, gfp_mask);
+ if (result < 0)
+ goto error_create;
+ usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe,
+ wtx->buf, wtx->buf_size, i1480u_tx_cb, wtx);
+ } else {
+ result = i1480u_tx_create_1(wtx, skb, gfp_mask);
+ if (result < 0)
+ goto error_create;
+ usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe,
+ skb->data, skb->len, i1480u_tx_cb, wtx);
+ }
+ spin_lock_irqsave(&i1480u->tx_list_lock, flags);
+ list_add(&wtx->list_node, &i1480u->tx_list);
+ spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
+ return wtx;
+
+error_create:
+ kfree(wtx->urb);
+error_urb_alloc:
+ kfree(wtx);
+error_wtx_alloc:
+ return NULL;
+}
+
+/**
+ * Actual fragmentation and transmission of frame
+ *
+ * @wlp: WLP substack data structure
+ * @skb: To be transmitted
+ * @dst: Device address of destination
+ * @returns: 0 on success, <0 on failure
+ *
+ * This function can also be called directly (not just from
+ * hard_start_xmit), so we also check here if the interface is up before
+ * taking sending anything.
+ */
+int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb,
+ struct uwb_dev_addr *dst)
+{
+ int result = -ENXIO;
+ struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
+ struct device *dev = &i1480u->usb_iface->dev;
+ struct net_device *net_dev = i1480u->net_dev;
+ struct i1480u_tx *wtx;
+ struct wlp_tx_hdr *wlp_tx_hdr;
+ static unsigned char dev_bcast[2] = { 0xff, 0xff };
+#if 0
+ int lockup = 50;
+#endif
+
+ d_fnstart(6, dev, "(skb %p (%u), net_dev %p)\n", skb, skb->len,
+ net_dev);
+ BUG_ON(i1480u->wlp.rc == NULL);
+ if ((net_dev->flags & IFF_UP) == 0)
+ goto out;
+ result = -EBUSY;
+ if (atomic_read(&i1480u->tx_inflight.count) >= i1480u->tx_inflight.max) {
+ if (d_test(2) && printk_ratelimit())
+ d_printf(2, dev, "Max frames in flight "
+ "stopping queue.\n");
+ netif_stop_queue(net_dev);
+ goto error_max_inflight;
+ }
+ result = -ENOMEM;
+ wtx = i1480u_tx_create(i1480u, skb, GFP_ATOMIC);
+ if (unlikely(wtx == NULL)) {
+ if (printk_ratelimit())
+ dev_err(dev, "TX: no memory for WLP TX URB,"
+ "dropping packet (in flight %d)\n",
+ atomic_read(&i1480u->tx_inflight.count));
+ netif_stop_queue(net_dev);
+ goto error_wtx_alloc;
+ }
+ wtx->i1480u = i1480u;
+ /* Fill out the i1480 header; @i1480u->def_tx_hdr read without
+ * locking. We do so because they are kind of orthogonal to
+ * each other (and thus not changed in an atomic batch).
+ * The ETH header is right after the WLP TX header. */
+ wlp_tx_hdr = wtx->wlp_tx_hdr;
+ *wlp_tx_hdr = i1480u->options.def_tx_hdr;
+ wlp_tx_hdr->dstaddr = *dst;
+ if (!memcmp(&wlp_tx_hdr->dstaddr, dev_bcast, sizeof(dev_bcast))
+ && (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)) {
+ /*Broadcast message directed to DRP host. Send as best effort
+ * on PCA. */
+ wlp_tx_hdr_set_delivery_id_type(wlp_tx_hdr, i1480u->options.pca_base_priority);
+ }
+
+#if 0
+ dev_info(dev, "TX delivering skb -> USB, %zu bytes\n", skb->len);
+ dump_bytes(dev, skb->data, skb->len > 72 ? 72 : skb->len);
+#endif
+#if 0
+ /* simulates a device lockup after every lockup# packets */
+ if (lockup && ((i1480u->stats.tx_packets + 1) % lockup) == 0) {
+ /* Simulate a dropped transmit interrupt */
+ net_dev->trans_start = jiffies;
+ netif_stop_queue(net_dev);
+ dev_err(dev, "Simulate lockup at %ld\n", jiffies);
+ return result;
+ }
+#endif
+
+ result = usb_submit_urb(wtx->urb, GFP_ATOMIC); /* Go baby */
+ if (result < 0) {
+ dev_err(dev, "TX: cannot submit URB: %d\n", result);
+ /* We leave the freeing of skb to calling function */
+ wtx->skb = NULL;
+ goto error_tx_urb_submit;
+ }
+ atomic_inc(&i1480u->tx_inflight.count);
+ net_dev->trans_start = jiffies;
+ d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len,
+ net_dev, result);
+ return result;
+
+error_tx_urb_submit:
+ i1480u_tx_destroy(i1480u, wtx);
+error_wtx_alloc:
+error_max_inflight:
+out:
+ d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len,
+ net_dev, result);
+ return result;
+}
+
+
+/**
+ * Transmit an skb Called when an skbuf has to be transmitted
+ *
+ * The skb is first passed to WLP substack to ensure this is a valid
+ * frame. If valid the device address of destination will be filled and
+ * the WLP header prepended to the skb. If this step fails we fake sending
+ * the frame, if we return an error the network stack will just keep trying.
+ *
+ * Broadcast frames inside a WSS needs to be treated special as multicast is
+ * not supported. A broadcast frame is sent as unicast to each member of the
+ * WSS - this is done by the WLP substack when it finds a broadcast frame.
+ * So, we test if the WLP substack took over the skb and only transmit it
+ * if it has not (been taken over).
+ *
+ * @net_dev->xmit_lock is held
+ */
+int i1480u_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
+{
+ int result;
+ struct i1480u *i1480u = netdev_priv(net_dev);
+ struct device *dev = &i1480u->usb_iface->dev;
+ struct uwb_dev_addr dst;
+
+ d_fnstart(6, dev, "(skb %p (%u), net_dev %p)\n", skb, skb->len,
+ net_dev);
+ BUG_ON(i1480u->wlp.rc == NULL);
+ if ((net_dev->flags & IFF_UP) == 0)
+ goto error;
+ result = wlp_prepare_tx_frame(dev, &i1480u->wlp, skb, &dst);
+ if (result < 0) {
+ dev_err(dev, "WLP verification of TX frame failed (%d). "
+ "Dropping packet.\n", result);
+ goto error;
+ } else if (result == 1) {
+ d_printf(6, dev, "WLP will transmit frame. \n");
+ /* trans_start time will be set when WLP actually transmits
+ * the frame */
+ goto out;
+ }
+ d_printf(6, dev, "Transmitting frame. \n");
+ result = i1480u_xmit_frame(&i1480u->wlp, skb, &dst);
+ if (result < 0) {
+ dev_err(dev, "Frame TX failed (%d).\n", result);
+ goto error;
+ }
+ d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len,
+ net_dev, result);
+ return NETDEV_TX_OK;
+error:
+ dev_kfree_skb_any(skb);
+ i1480u->stats.tx_dropped++;
+out:
+ d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len,
+ net_dev, result);
+ return NETDEV_TX_OK;
+}
+
+
+/**
+ * Called when a pkt transmission doesn't complete in a reasonable period
+ * Device reset may sleep - do it outside of interrupt context (delayed)
+ */
+void i1480u_tx_timeout(struct net_device *net_dev)
+{
+ struct i1480u *i1480u = netdev_priv(net_dev);
+
+ wlp_reset_all(&i1480u->wlp);
+}
+
+
+void i1480u_tx_release(struct i1480u *i1480u)
+{
+ unsigned long flags;
+ struct i1480u_tx *wtx, *next;
+ int count = 0, empty;
+
+ spin_lock_irqsave(&i1480u->tx_list_lock, flags);
+ list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) {
+ count++;
+ usb_unlink_urb(wtx->urb);
+ }
+ spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
+ count = count*10; /* i1480ut 200ms per unlinked urb (intervals of 20ms) */
+ /*
+ * We don't like this sollution too much (dirty as it is), but
+ * it is cheaper than putting a refcount on each i1480u_tx and
+ * i1480uting for all of them to go away...
+ *
+ * Called when no more packets can be added to tx_list
+ * so can i1480ut for it to be empty.
+ */
+ while (1) {
+ spin_lock_irqsave(&i1480u->tx_list_lock, flags);
+ empty = list_empty(&i1480u->tx_list);
+ spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
+ if (empty)
+ break;
+ count--;
+ BUG_ON(count == 0);
+ msleep(20);
+ }
+}
diff --git a/drivers/uwb/ie.c b/drivers/uwb/ie.c
new file mode 100644
index 00000000000..cf6f3d152b9
--- /dev/null
+++ b/drivers/uwb/ie.c
@@ -0,0 +1,541 @@
+/*
+ * Ultra Wide Band
+ * Information Element Handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Reinette Chatre <reinette.chatre@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.
+ *
+ *
+ * FIXME: docs
+ */
+
+#include "uwb-internal.h"
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+/**
+ * uwb_ie_next - get the next IE in a buffer
+ * @ptr: start of the buffer containing the IE data
+ * @len: length of the buffer
+ *
+ * Both @ptr and @len are updated so subsequent calls to uwb_ie_next()
+ * will get the next IE.
+ *
+ * NULL is returned (and @ptr and @len will not be updated) if there
+ * are no more IEs in the buffer or the buffer is too short.
+ */
+struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len)
+{
+ struct uwb_ie_hdr *hdr;
+ size_t ie_len;
+
+ if (*len < sizeof(struct uwb_ie_hdr))
+ return NULL;
+
+ hdr = *ptr;
+ ie_len = sizeof(struct uwb_ie_hdr) + hdr->length;
+
+ if (*len < ie_len)
+ return NULL;
+
+ *ptr += ie_len;
+ *len -= ie_len;
+
+ return hdr;
+}
+EXPORT_SYMBOL_GPL(uwb_ie_next);
+
+/**
+ * Get the IEs that a radio controller is sending in its beacon
+ *
+ * @uwb_rc: UWB Radio Controller
+ * @returns: Size read from the system
+ *
+ * We don't need to lock the uwb_rc's mutex because we don't modify
+ * anything. Once done with the iedata buffer, call
+ * uwb_rc_ie_release(iedata). Don't call kfree on it.
+ */
+ssize_t uwb_rc_get_ie(struct uwb_rc *uwb_rc, struct uwb_rc_evt_get_ie **pget_ie)
+{
+ ssize_t result;
+ struct device *dev = &uwb_rc->uwb_dev.dev;
+ struct uwb_rccb *cmd = NULL;
+ struct uwb_rceb *reply = NULL;
+ struct uwb_rc_evt_get_ie *get_ie;
+
+ d_fnstart(3, dev, "(%p, %p)\n", uwb_rc, pget_ie);
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_kzalloc;
+ cmd->bCommandType = UWB_RC_CET_GENERAL;
+ cmd->wCommand = cpu_to_le16(UWB_RC_CMD_GET_IE);
+ result = uwb_rc_vcmd(uwb_rc, "GET_IE", cmd, sizeof(*cmd),
+ UWB_RC_CET_GENERAL, UWB_RC_CMD_GET_IE,
+ &reply);
+ if (result < 0)
+ goto error_cmd;
+ get_ie = container_of(reply, struct uwb_rc_evt_get_ie, rceb);
+ if (result < sizeof(*get_ie)) {
+ dev_err(dev, "not enough data returned for decoding GET IE "
+ "(%zu bytes received vs %zu needed)\n",
+ result, sizeof(*get_ie));
+ result = -EINVAL;
+ } else if (result < sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)) {
+ dev_err(dev, "not enough data returned for decoding GET IE "
+ "payload (%zu bytes received vs %zu needed)\n", result,
+ sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength));
+ result = -EINVAL;
+ } else
+ *pget_ie = get_ie;
+error_cmd:
+ kfree(cmd);
+error_kzalloc:
+ d_fnend(3, dev, "(%p, %p) = %d\n", uwb_rc, pget_ie, (int)result);
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_get_ie);
+
+
+/*
+ * Given a pointer to an IE, print it in ASCII/hex followed by a new line
+ *
+ * @ie_hdr: pointer to the IE header. Length is in there, and it is
+ * guaranteed that the ie_hdr->length bytes following it are
+ * safely accesible.
+ *
+ * @_data: context data passed from uwb_ie_for_each(), an struct output_ctx
+ */
+int uwb_ie_dump_hex(struct uwb_dev *uwb_dev, const struct uwb_ie_hdr *ie_hdr,
+ size_t offset, void *_ctx)
+{
+ struct uwb_buf_ctx *ctx = _ctx;
+ const u8 *pl = (void *)(ie_hdr + 1);
+ u8 pl_itr;
+
+ ctx->bytes += scnprintf(ctx->buf + ctx->bytes, ctx->size - ctx->bytes,
+ "%02x %02x ", (unsigned) ie_hdr->element_id,
+ (unsigned) ie_hdr->length);
+ pl_itr = 0;
+ while (pl_itr < ie_hdr->length && ctx->bytes < ctx->size)
+ ctx->bytes += scnprintf(ctx->buf + ctx->bytes,
+ ctx->size - ctx->bytes,
+ "%02x ", (unsigned) pl[pl_itr++]);
+ if (ctx->bytes < ctx->size)
+ ctx->buf[ctx->bytes++] = '\n';
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_ie_dump_hex);
+
+
+/**
+ * Verify that a pointer in a buffer points to valid IE
+ *
+ * @start: pointer to start of buffer in which IE appears
+ * @itr: pointer to IE inside buffer that will be verified
+ * @top: pointer to end of buffer
+ *
+ * @returns: 0 if IE is valid, <0 otherwise
+ *
+ * Verification involves checking that the buffer can contain a
+ * header and the amount of data reported in the IE header can be found in
+ * the buffer.
+ */
+static
+int uwb_rc_ie_verify(struct uwb_dev *uwb_dev, const void *start,
+ const void *itr, const void *top)
+{
+ struct device *dev = &uwb_dev->dev;
+ const struct uwb_ie_hdr *ie_hdr;
+
+ if (top - itr < sizeof(*ie_hdr)) {
+ dev_err(dev, "Bad IE: no data to decode header "
+ "(%zu bytes left vs %zu needed) at offset %zu\n",
+ top - itr, sizeof(*ie_hdr), itr - start);
+ return -EINVAL;
+ }
+ ie_hdr = itr;
+ itr += sizeof(*ie_hdr);
+ if (top - itr < ie_hdr->length) {
+ dev_err(dev, "Bad IE: not enough data for payload "
+ "(%zu bytes left vs %zu needed) at offset %zu\n",
+ top - itr, (size_t)ie_hdr->length,
+ (void *)ie_hdr - start);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+/**
+ * Walk a buffer filled with consecutive IE's a buffer
+ *
+ * @uwb_dev: UWB device this IEs belong to (for err messages mainly)
+ *
+ * @fn: function to call with each IE; if it returns 0, we keep
+ * traversing the buffer. If it returns !0, we'll stop and return
+ * that value.
+ *
+ * @data: pointer passed to @fn
+ *
+ * @buf: buffer where the consecutive IEs are located
+ *
+ * @size: size of @buf
+ *
+ * Each IE is checked for basic correctness (there is space left for
+ * the header and the payload). If that test is failed, we stop
+ * processing. For every good IE, @fn is called.
+ */
+ssize_t uwb_ie_for_each(struct uwb_dev *uwb_dev, uwb_ie_f fn, void *data,
+ const void *buf, size_t size)
+{
+ ssize_t result = 0;
+ const struct uwb_ie_hdr *ie_hdr;
+ const void *itr = buf, *top = itr + size;
+
+ while (itr < top) {
+ if (uwb_rc_ie_verify(uwb_dev, buf, itr, top) != 0)
+ break;
+ ie_hdr = itr;
+ itr += sizeof(*ie_hdr) + ie_hdr->length;
+ result = fn(uwb_dev, ie_hdr, itr - buf, data);
+ if (result != 0)
+ break;
+ }
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_ie_for_each);
+
+
+/**
+ * Replace all IEs currently being transmitted by a device
+ *
+ * @cmd: pointer to the SET-IE command with the IEs to set
+ * @size: size of @buf
+ */
+int uwb_rc_set_ie(struct uwb_rc *rc, struct uwb_rc_cmd_set_ie *cmd)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_evt_set_ie reply;
+
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_SET_IE;
+ result = uwb_rc_cmd(rc, "SET-IE", &cmd->rccb,
+ sizeof(*cmd) + le16_to_cpu(cmd->wIELength),
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ else if (result != sizeof(reply)) {
+ dev_err(dev, "SET-IE: not enough data to decode reply "
+ "(%d bytes received vs %zu needed)\n",
+ result, sizeof(reply));
+ result = -EIO;
+ } else if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(dev, "SET-IE: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ } else
+ result = 0;
+error_cmd:
+ return result;
+}
+
+/**
+ * Determine by IE id if IE is host settable
+ * WUSB 1.0 [8.6.2.8 Table 8.85]
+ *
+ * EXCEPTION:
+ * All but UWB_IE_WLP appears in Table 8.85 from WUSB 1.0. Setting this IE
+ * is required for the WLP substack to perform association with its WSS so
+ * we hope that the WUSB spec will be changed to reflect this.
+ */
+static
+int uwb_rc_ie_is_host_settable(enum uwb_ie element_id)
+{
+ if (element_id == UWB_PCA_AVAILABILITY ||
+ element_id == UWB_BP_SWITCH_IE ||
+ element_id == UWB_MAC_CAPABILITIES_IE ||
+ element_id == UWB_PHY_CAPABILITIES_IE ||
+ element_id == UWB_APP_SPEC_PROBE_IE ||
+ element_id == UWB_IDENTIFICATION_IE ||
+ element_id == UWB_MASTER_KEY_ID_IE ||
+ element_id == UWB_IE_WLP ||
+ element_id == UWB_APP_SPEC_IE)
+ return 1;
+ return 0;
+}
+
+
+/**
+ * Extract Host Settable IEs from IE
+ *
+ * @ie_data: pointer to buffer containing all IEs
+ * @size: size of buffer
+ *
+ * @returns: length of buffer that only includes host settable IEs
+ *
+ * Given a buffer of IEs we move all Host Settable IEs to front of buffer
+ * by overwriting the IEs that are not Host Settable.
+ * Buffer length is adjusted accordingly.
+ */
+static
+ssize_t uwb_rc_parse_host_settable_ie(struct uwb_dev *uwb_dev,
+ void *ie_data, size_t size)
+{
+ size_t new_len = size;
+ struct uwb_ie_hdr *ie_hdr;
+ size_t ie_length;
+ void *itr = ie_data, *top = itr + size;
+
+ while (itr < top) {
+ if (uwb_rc_ie_verify(uwb_dev, ie_data, itr, top) != 0)
+ break;
+ ie_hdr = itr;
+ ie_length = sizeof(*ie_hdr) + ie_hdr->length;
+ if (uwb_rc_ie_is_host_settable(ie_hdr->element_id)) {
+ itr += ie_length;
+ } else {
+ memmove(itr, itr + ie_length, top - (itr + ie_length));
+ new_len -= ie_length;
+ top -= ie_length;
+ }
+ }
+ return new_len;
+}
+
+
+/* Cleanup the whole IE management subsystem */
+void uwb_rc_ie_init(struct uwb_rc *uwb_rc)
+{
+ mutex_init(&uwb_rc->ies_mutex);
+}
+
+
+/**
+ * Set up cache for host settable IEs currently being transmitted
+ *
+ * First we just call GET-IE to get the current IEs being transmitted
+ * (or we workaround and pretend we did) and (because the format is
+ * the same) reuse that as the IE cache (with the command prefix, as
+ * explained in 'struct uwb_rc').
+ *
+ * @returns: size of cache created
+ */
+ssize_t uwb_rc_ie_setup(struct uwb_rc *uwb_rc)
+{
+ struct device *dev = &uwb_rc->uwb_dev.dev;
+ ssize_t result;
+ size_t capacity;
+ struct uwb_rc_evt_get_ie *ie_info;
+
+ d_fnstart(3, dev, "(%p)\n", uwb_rc);
+ mutex_lock(&uwb_rc->ies_mutex);
+ result = uwb_rc_get_ie(uwb_rc, &ie_info);
+ if (result < 0)
+ goto error_get_ie;
+ capacity = result;
+ d_printf(5, dev, "Got IEs %zu bytes (%zu long at %p)\n", result,
+ (size_t)le16_to_cpu(ie_info->wIELength), ie_info);
+
+ /* Remove IEs that host should not set. */
+ result = uwb_rc_parse_host_settable_ie(&uwb_rc->uwb_dev,
+ ie_info->IEData, le16_to_cpu(ie_info->wIELength));
+ if (result < 0)
+ goto error_parse;
+ d_printf(5, dev, "purged non-settable IEs to %zu bytes\n", result);
+ uwb_rc->ies = (void *) ie_info;
+ uwb_rc->ies->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ uwb_rc->ies->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_IE);
+ uwb_rc->ies_capacity = capacity;
+ d_printf(5, dev, "IE cache at %p %zu bytes, %zu capacity\n",
+ ie_info, result, capacity);
+ result = 0;
+error_parse:
+error_get_ie:
+ mutex_unlock(&uwb_rc->ies_mutex);
+ d_fnend(3, dev, "(%p) = %zu\n", uwb_rc, result);
+ return result;
+}
+
+
+/* Cleanup the whole IE management subsystem */
+void uwb_rc_ie_release(struct uwb_rc *uwb_rc)
+{
+ kfree(uwb_rc->ies);
+ uwb_rc->ies = NULL;
+ uwb_rc->ies_capacity = 0;
+}
+
+
+static
+int __acc_size(struct uwb_dev *uwb_dev, const struct uwb_ie_hdr *ie_hdr,
+ size_t offset, void *_ctx)
+{
+ size_t *acc_size = _ctx;
+ *acc_size += sizeof(*ie_hdr) + ie_hdr->length;
+ d_printf(6, &uwb_dev->dev, "new acc size %zu\n", *acc_size);
+ return 0;
+}
+
+
+/**
+ * Add a new IE to IEs currently being transmitted by device
+ *
+ * @ies: the buffer containing the new IE or IEs to be added to
+ * the device's beacon. The buffer will be verified for
+ * consistence (meaning the headers should be right) and
+ * consistent with the buffer size.
+ * @size: size of @ies (in bytes, total buffer size)
+ * @returns: 0 if ok, <0 errno code on error
+ *
+ * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
+ * after the device sent the first beacon that includes the IEs specified
+ * in the SET IE command. We thus cannot send this command if the device is
+ * not beaconing. Instead, a SET IE command will be sent later right after
+ * we start beaconing.
+ *
+ * Setting an IE on the device will overwrite all current IEs in device. So
+ * we take the current IEs being transmitted by the device, append the
+ * new one, and call SET IE with all the IEs needed.
+ *
+ * The local IE cache will only be updated with the new IE if SET IE
+ * completed successfully.
+ */
+int uwb_rc_ie_add(struct uwb_rc *uwb_rc,
+ const struct uwb_ie_hdr *ies, size_t size)
+{
+ int result = 0;
+ struct device *dev = &uwb_rc->uwb_dev.dev;
+ struct uwb_rc_cmd_set_ie *new_ies;
+ size_t ies_size, total_size, acc_size = 0;
+
+ if (uwb_rc->ies == NULL)
+ return -ESHUTDOWN;
+ uwb_ie_for_each(&uwb_rc->uwb_dev, __acc_size, &acc_size, ies, size);
+ if (acc_size != size) {
+ dev_err(dev, "BUG: bad IEs, misconstructed headers "
+ "[%zu bytes reported vs %zu calculated]\n",
+ size, acc_size);
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ mutex_lock(&uwb_rc->ies_mutex);
+ ies_size = le16_to_cpu(uwb_rc->ies->wIELength);
+ total_size = sizeof(*uwb_rc->ies) + ies_size;
+ if (total_size + size > uwb_rc->ies_capacity) {
+ d_printf(4, dev, "Reallocating IE cache from %p capacity %zu "
+ "to capacity %zu\n", uwb_rc->ies, uwb_rc->ies_capacity,
+ total_size + size);
+ new_ies = kzalloc(total_size + size, GFP_KERNEL);
+ if (new_ies == NULL) {
+ dev_err(dev, "No memory for adding new IE\n");
+ result = -ENOMEM;
+ goto error_alloc;
+ }
+ memcpy(new_ies, uwb_rc->ies, total_size);
+ uwb_rc->ies_capacity = total_size + size;
+ kfree(uwb_rc->ies);
+ uwb_rc->ies = new_ies;
+ d_printf(4, dev, "New IE cache at %p capacity %zu\n",
+ uwb_rc->ies, uwb_rc->ies_capacity);
+ }
+ memcpy((void *)uwb_rc->ies + total_size, ies, size);
+ uwb_rc->ies->wIELength = cpu_to_le16(ies_size + size);
+ if (uwb_rc->beaconing != -1) {
+ result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
+ if (result < 0) {
+ dev_err(dev, "Cannot set new IE on device: %d\n",
+ result);
+ uwb_rc->ies->wIELength = cpu_to_le16(ies_size);
+ } else
+ result = 0;
+ }
+ d_printf(4, dev, "IEs now occupy %hu bytes of %zu capacity at %p\n",
+ le16_to_cpu(uwb_rc->ies->wIELength), uwb_rc->ies_capacity,
+ uwb_rc->ies);
+error_alloc:
+ mutex_unlock(&uwb_rc->ies_mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_ie_add);
+
+
+/*
+ * Remove an IE from internal cache
+ *
+ * We are dealing with our internal IE cache so no need to verify that the
+ * IEs are valid (it has been done already).
+ *
+ * Should be called with ies_mutex held
+ *
+ * We do not break out once an IE is found in the cache. It is currently
+ * possible to have more than one IE with the same ID included in the
+ * beacon. We don't reallocate, we just mark the size smaller.
+ */
+static
+int uwb_rc_ie_cache_rm(struct uwb_rc *uwb_rc, enum uwb_ie to_remove)
+{
+ struct uwb_ie_hdr *ie_hdr;
+ size_t new_len = le16_to_cpu(uwb_rc->ies->wIELength);
+ void *itr = uwb_rc->ies->IEData;
+ void *top = itr + new_len;
+
+ while (itr < top) {
+ ie_hdr = itr;
+ if (ie_hdr->element_id != to_remove) {
+ itr += sizeof(*ie_hdr) + ie_hdr->length;
+ } else {
+ int ie_length;
+ ie_length = sizeof(*ie_hdr) + ie_hdr->length;
+ if (top - itr != ie_length)
+ memmove(itr, itr + ie_length, top - itr + ie_length);
+ top -= ie_length;
+ new_len -= ie_length;
+ }
+ }
+ uwb_rc->ies->wIELength = cpu_to_le16(new_len);
+ return 0;
+}
+
+
+/**
+ * Remove an IE currently being transmitted by device
+ *
+ * @element_id: id of IE to be removed from device's beacon
+ */
+int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id)
+{
+ struct device *dev = &uwb_rc->uwb_dev.dev;
+ int result;
+
+ if (uwb_rc->ies == NULL)
+ return -ESHUTDOWN;
+ mutex_lock(&uwb_rc->ies_mutex);
+ result = uwb_rc_ie_cache_rm(uwb_rc, element_id);
+ if (result < 0)
+ dev_err(dev, "Cannot remove IE from cache.\n");
+ if (uwb_rc->beaconing != -1) {
+ result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
+ if (result < 0)
+ dev_err(dev, "Cannot set new IE on device.\n");
+ }
+ mutex_unlock(&uwb_rc->ies_mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_ie_rm);
diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c
new file mode 100644
index 00000000000..15f856c9689
--- /dev/null
+++ b/drivers/uwb/lc-dev.c
@@ -0,0 +1,492 @@
+/*
+ * Ultra Wide Band
+ * Life cycle of devices
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/random.h>
+#include "uwb-internal.h"
+
+#define D_LOCAL 1
+#include <linux/uwb/debug.h>
+
+
+/* We initialize addresses to 0xff (invalid, as it is bcast) */
+static inline void uwb_dev_addr_init(struct uwb_dev_addr *addr)
+{
+ memset(&addr->data, 0xff, sizeof(addr->data));
+}
+
+static inline void uwb_mac_addr_init(struct uwb_mac_addr *addr)
+{
+ memset(&addr->data, 0xff, sizeof(addr->data));
+}
+
+/* @returns !0 if a device @addr is a broadcast address */
+static inline int uwb_dev_addr_bcast(const struct uwb_dev_addr *addr)
+{
+ static const struct uwb_dev_addr bcast = { .data = { 0xff, 0xff } };
+ return !uwb_dev_addr_cmp(addr, &bcast);
+}
+
+/*
+ * Add callback @new to be called when an event occurs in @rc.
+ */
+int uwb_notifs_register(struct uwb_rc *rc, struct uwb_notifs_handler *new)
+{
+ if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+ return -ERESTARTSYS;
+ list_add(&new->list_node, &rc->notifs_chain.list);
+ mutex_unlock(&rc->notifs_chain.mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_notifs_register);
+
+/*
+ * Remove event handler (callback)
+ */
+int uwb_notifs_deregister(struct uwb_rc *rc, struct uwb_notifs_handler *entry)
+{
+ if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+ return -ERESTARTSYS;
+ list_del(&entry->list_node);
+ mutex_unlock(&rc->notifs_chain.mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_notifs_deregister);
+
+/*
+ * Notify all event handlers of a given event on @rc
+ *
+ * We are called with a valid reference to the device, or NULL if the
+ * event is not for a particular event (e.g., a BG join event).
+ */
+void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event)
+{
+ struct uwb_notifs_handler *handler;
+ if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+ return;
+ if (!list_empty(&rc->notifs_chain.list)) {
+ list_for_each_entry(handler, &rc->notifs_chain.list, list_node) {
+ handler->cb(handler->data, uwb_dev, event);
+ }
+ }
+ mutex_unlock(&rc->notifs_chain.mutex);
+}
+
+/*
+ * Release the backing device of a uwb_dev that has been dynamically allocated.
+ */
+static void uwb_dev_sys_release(struct device *dev)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+ d_fnstart(4, NULL, "(dev %p uwb_dev %p)\n", dev, uwb_dev);
+ uwb_bce_put(uwb_dev->bce);
+ d_printf(0, &uwb_dev->dev, "uwb_dev %p freed\n", uwb_dev);
+ memset(uwb_dev, 0x69, sizeof(*uwb_dev));
+ kfree(uwb_dev);
+ d_fnend(4, NULL, "(dev %p uwb_dev %p) = void\n", dev, uwb_dev);
+}
+
+/*
+ * Initialize a UWB device instance
+ *
+ * Alloc, zero and call this function.
+ */
+void uwb_dev_init(struct uwb_dev *uwb_dev)
+{
+ mutex_init(&uwb_dev->mutex);
+ device_initialize(&uwb_dev->dev);
+ uwb_dev->dev.release = uwb_dev_sys_release;
+ uwb_dev_addr_init(&uwb_dev->dev_addr);
+ uwb_mac_addr_init(&uwb_dev->mac_addr);
+ bitmap_fill(uwb_dev->streams, UWB_NUM_GLOBAL_STREAMS);
+}
+
+static ssize_t uwb_dev_EUI_48_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ char addr[UWB_ADDR_STRSIZE];
+
+ uwb_mac_addr_print(addr, sizeof(addr), &uwb_dev->mac_addr);
+ return sprintf(buf, "%s\n", addr);
+}
+static DEVICE_ATTR(EUI_48, S_IRUGO, uwb_dev_EUI_48_show, NULL);
+
+static ssize_t uwb_dev_DevAddr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ char addr[UWB_ADDR_STRSIZE];
+
+ uwb_dev_addr_print(addr, sizeof(addr), &uwb_dev->dev_addr);
+ return sprintf(buf, "%s\n", addr);
+}
+static DEVICE_ATTR(DevAddr, S_IRUGO, uwb_dev_DevAddr_show, NULL);
+
+/*
+ * Show the BPST of this device.
+ *
+ * Calculated from the receive time of the device's beacon and it's
+ * slot number.
+ */
+static ssize_t uwb_dev_BPST_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce;
+ struct uwb_beacon_frame *bf;
+ u16 bpst;
+
+ bce = uwb_dev->bce;
+ mutex_lock(&bce->mutex);
+ bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
+ bpst = bce->be->wBPSTOffset
+ - (u16)(bf->Beacon_Slot_Number * UWB_BEACON_SLOT_LENGTH_US);
+ mutex_unlock(&bce->mutex);
+
+ return sprintf(buf, "%d\n", bpst);
+}
+static DEVICE_ATTR(BPST, S_IRUGO, uwb_dev_BPST_show, NULL);
+
+/*
+ * Show the IEs a device is beaconing
+ *
+ * We need to access the beacon cache, so we just lock it really
+ * quick, print the IEs and unlock.
+ *
+ * We have a reference on the cache entry, so that should be
+ * quite safe.
+ */
+static ssize_t uwb_dev_IEs_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+ return uwb_bce_print_IEs(uwb_dev, uwb_dev->bce, buf, PAGE_SIZE);
+}
+static DEVICE_ATTR(IEs, S_IRUGO | S_IWUSR, uwb_dev_IEs_show, NULL);
+
+static ssize_t uwb_dev_LQE_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce = uwb_dev->bce;
+ size_t result;
+
+ mutex_lock(&bce->mutex);
+ result = stats_show(&uwb_dev->bce->lqe_stats, buf);
+ mutex_unlock(&bce->mutex);
+ return result;
+}
+
+static ssize_t uwb_dev_LQE_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce = uwb_dev->bce;
+ ssize_t result;
+
+ mutex_lock(&bce->mutex);
+ result = stats_store(&uwb_dev->bce->lqe_stats, buf, size);
+ mutex_unlock(&bce->mutex);
+ return result;
+}
+static DEVICE_ATTR(LQE, S_IRUGO | S_IWUSR, uwb_dev_LQE_show, uwb_dev_LQE_store);
+
+static ssize_t uwb_dev_RSSI_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce = uwb_dev->bce;
+ size_t result;
+
+ mutex_lock(&bce->mutex);
+ result = stats_show(&uwb_dev->bce->rssi_stats, buf);
+ mutex_unlock(&bce->mutex);
+ return result;
+}
+
+static ssize_t uwb_dev_RSSI_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_beca_e *bce = uwb_dev->bce;
+ ssize_t result;
+
+ mutex_lock(&bce->mutex);
+ result = stats_store(&uwb_dev->bce->rssi_stats, buf, size);
+ mutex_unlock(&bce->mutex);
+ return result;
+}
+static DEVICE_ATTR(RSSI, S_IRUGO | S_IWUSR, uwb_dev_RSSI_show, uwb_dev_RSSI_store);
+
+
+static struct attribute *dev_attrs[] = {
+ &dev_attr_EUI_48.attr,
+ &dev_attr_DevAddr.attr,
+ &dev_attr_BPST.attr,
+ &dev_attr_IEs.attr,
+ &dev_attr_LQE.attr,
+ &dev_attr_RSSI.attr,
+ NULL,
+};
+
+static struct attribute_group dev_attr_group = {
+ .attrs = dev_attrs,
+};
+
+static struct attribute_group *groups[] = {
+ &dev_attr_group,
+ NULL,
+};
+
+/**
+ * Device SYSFS registration
+ *
+ *
+ */
+static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev)
+{
+ int result;
+ struct device *dev;
+
+ d_fnstart(4, NULL, "(uwb_dev %p parent_dev %p)\n", uwb_dev, parent_dev);
+ BUG_ON(parent_dev == NULL);
+
+ dev = &uwb_dev->dev;
+ /* Device sysfs files are only useful for neighbor devices not
+ local radio controllers. */
+ if (&uwb_dev->rc->uwb_dev != uwb_dev)
+ dev->groups = groups;
+ dev->parent = parent_dev;
+ dev_set_drvdata(dev, uwb_dev);
+
+ result = device_add(dev);
+ d_fnend(4, NULL, "(uwb_dev %p parent_dev %p) = %d\n", uwb_dev, parent_dev, result);
+ return result;
+}
+
+
+static void __uwb_dev_sys_rm(struct uwb_dev *uwb_dev)
+{
+ d_fnstart(4, NULL, "(uwb_dev %p)\n", uwb_dev);
+ dev_set_drvdata(&uwb_dev->dev, NULL);
+ device_del(&uwb_dev->dev);
+ d_fnend(4, NULL, "(uwb_dev %p) = void\n", uwb_dev);
+}
+
+
+/**
+ * Register and initialize a new UWB device
+ *
+ * Did you call uwb_dev_init() on it?
+ *
+ * @parent_rc: is the parent radio controller who has the link to the
+ * device. When registering the UWB device that is a UWB
+ * Radio Controller, we point back to it.
+ *
+ * If registering the device that is part of a radio, caller has set
+ * rc->uwb_dev->dev. Otherwise it is to be left NULL--a new one will
+ * be allocated.
+ */
+int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
+ struct uwb_rc *parent_rc)
+{
+ int result;
+ struct device *dev;
+
+ BUG_ON(uwb_dev == NULL);
+ BUG_ON(parent_dev == NULL);
+ BUG_ON(parent_rc == NULL);
+
+ mutex_lock(&uwb_dev->mutex);
+ dev = &uwb_dev->dev;
+ uwb_dev->rc = parent_rc;
+ result = __uwb_dev_sys_add(uwb_dev, parent_dev);
+ if (result < 0)
+ printk(KERN_ERR "UWB: unable to register dev %s with sysfs: %d\n",
+ dev_name(dev), result);
+ mutex_unlock(&uwb_dev->mutex);
+ return result;
+}
+
+
+void uwb_dev_rm(struct uwb_dev *uwb_dev)
+{
+ mutex_lock(&uwb_dev->mutex);
+ __uwb_dev_sys_rm(uwb_dev);
+ mutex_unlock(&uwb_dev->mutex);
+}
+
+
+static
+int __uwb_dev_try_get(struct device *dev, void *__target_uwb_dev)
+{
+ struct uwb_dev *target_uwb_dev = __target_uwb_dev;
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ if (uwb_dev == target_uwb_dev) {
+ uwb_dev_get(uwb_dev);
+ return 1;
+ } else
+ return 0;
+}
+
+
+/**
+ * Given a UWB device descriptor, validate and refcount it
+ *
+ * @returns NULL if the device does not exist or is quiescing; the ptr to
+ * it otherwise.
+ */
+struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev)
+{
+ if (uwb_dev_for_each(rc, __uwb_dev_try_get, uwb_dev))
+ return uwb_dev;
+ else
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(uwb_dev_try_get);
+
+
+/**
+ * Remove a device from the system [grunt for other functions]
+ */
+int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc)
+{
+ struct device *dev = &uwb_dev->dev;
+ char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+ d_fnstart(3, NULL, "(dev %p [uwb_dev %p], uwb_rc %p)\n", dev, uwb_dev, rc);
+ uwb_mac_addr_print(macbuf, sizeof(macbuf), &uwb_dev->mac_addr);
+ uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr);
+ dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n",
+ macbuf, devbuf,
+ rc ? rc->uwb_dev.dev.parent->bus->name : "n/a",
+ rc ? dev_name(rc->uwb_dev.dev.parent) : "");
+ uwb_dev_rm(uwb_dev);
+ uwb_dev_put(uwb_dev); /* for the creation in _onair() */
+ d_fnend(3, NULL, "(dev %p [uwb_dev %p], uwb_rc %p) = 0\n", dev, uwb_dev, rc);
+ return 0;
+}
+
+
+/**
+ * A device went off the air, clean up after it!
+ *
+ * This is called by the UWB Daemon (through the beacon purge function
+ * uwb_bcn_cache_purge) when it is detected that a device has been in
+ * radio silence for a while.
+ *
+ * If this device is actually a local radio controller we don't need
+ * to go through the offair process, as it is not registered as that.
+ *
+ * NOTE: uwb_bcn_cache.mutex is held!
+ */
+void uwbd_dev_offair(struct uwb_beca_e *bce)
+{
+ struct uwb_dev *uwb_dev;
+
+ uwb_dev = bce->uwb_dev;
+ if (uwb_dev) {
+ uwb_notify(uwb_dev->rc, uwb_dev, UWB_NOTIF_OFFAIR);
+ __uwb_dev_offair(uwb_dev, uwb_dev->rc);
+ }
+}
+
+
+/**
+ * A device went on the air, start it up!
+ *
+ * This is called by the UWB Daemon when it is detected that a device
+ * has popped up in the radio range of the radio controller.
+ *
+ * It will just create the freaking device, register the beacon and
+ * stuff and yatla, done.
+ *
+ *
+ * NOTE: uwb_beca.mutex is held, bce->mutex is held
+ */
+void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_dev *uwb_dev;
+ char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+ uwb_mac_addr_print(macbuf, sizeof(macbuf), bce->mac_addr);
+ uwb_dev_addr_print(devbuf, sizeof(devbuf), &bce->dev_addr);
+ uwb_dev = kzalloc(sizeof(struct uwb_dev), GFP_KERNEL);
+ if (uwb_dev == NULL) {
+ dev_err(dev, "new device %s: Cannot allocate memory\n",
+ macbuf);
+ return;
+ }
+ uwb_dev_init(uwb_dev); /* This sets refcnt to one, we own it */
+ uwb_dev->mac_addr = *bce->mac_addr;
+ uwb_dev->dev_addr = bce->dev_addr;
+ dev_set_name(&uwb_dev->dev, macbuf);
+ result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc);
+ if (result < 0) {
+ dev_err(dev, "new device %s: cannot instantiate device\n",
+ macbuf);
+ goto error_dev_add;
+ }
+ /* plug the beacon cache */
+ bce->uwb_dev = uwb_dev;
+ uwb_dev->bce = bce;
+ uwb_bce_get(bce); /* released in uwb_dev_sys_release() */
+ dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n",
+ macbuf, devbuf, rc->uwb_dev.dev.parent->bus->name,
+ dev_name(rc->uwb_dev.dev.parent));
+ uwb_notify(rc, uwb_dev, UWB_NOTIF_ONAIR);
+ return;
+
+error_dev_add:
+ kfree(uwb_dev);
+ return;
+}
+
+/**
+ * Iterate over the list of UWB devices, calling a @function on each
+ *
+ * See docs for bus_for_each()....
+ *
+ * @rc: radio controller for the devices.
+ * @function: function to call.
+ * @priv: data to pass to @function.
+ * @returns: 0 if no invocation of function() returned a value
+ * different to zero. That value otherwise.
+ */
+int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f function, void *priv)
+{
+ return device_for_each_child(&rc->uwb_dev.dev, priv, function);
+}
+EXPORT_SYMBOL_GPL(uwb_dev_for_each);
diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c
new file mode 100644
index 00000000000..ee5772f00d4
--- /dev/null
+++ b/drivers/uwb/lc-rc.c
@@ -0,0 +1,495 @@
+/*
+ * Ultra Wide Band
+ * Life cycle of radio controllers
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: docs
+ *
+ * A UWB radio controller is also a UWB device, so it embeds one...
+ *
+ * List of RCs comes from the 'struct class uwb_rc_class'.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/random.h>
+#include <linux/kdev_t.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+
+#define D_LOCAL 1
+#include <linux/uwb/debug.h>
+#include "uwb-internal.h"
+
+static int uwb_rc_index_match(struct device *dev, void *data)
+{
+ int *index = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc->index == *index)
+ return 1;
+ return 0;
+}
+
+static struct uwb_rc *uwb_rc_find_by_index(int index)
+{
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+ dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match);
+ if (dev)
+ rc = dev_get_drvdata(dev);
+ return rc;
+}
+
+static int uwb_rc_new_index(void)
+{
+ int index = 0;
+
+ for (;;) {
+ if (!uwb_rc_find_by_index(index))
+ return index;
+ if (++index < 0)
+ index = 0;
+ }
+}
+
+/**
+ * Release the backing device of a uwb_rc that has been dynamically allocated.
+ */
+static void uwb_rc_sys_release(struct device *dev)
+{
+ struct uwb_dev *uwb_dev = container_of(dev, struct uwb_dev, dev);
+ struct uwb_rc *rc = container_of(uwb_dev, struct uwb_rc, uwb_dev);
+
+ uwb_rc_neh_destroy(rc);
+ uwb_rc_ie_release(rc);
+ d_printf(1, dev, "freed uwb_rc %p\n", rc);
+ kfree(rc);
+}
+
+
+void uwb_rc_init(struct uwb_rc *rc)
+{
+ struct uwb_dev *uwb_dev = &rc->uwb_dev;
+
+ uwb_dev_init(uwb_dev);
+ rc->uwb_dev.dev.class = &uwb_rc_class;
+ rc->uwb_dev.dev.release = uwb_rc_sys_release;
+ uwb_rc_neh_create(rc);
+ rc->beaconing = -1;
+ rc->scan_type = UWB_SCAN_DISABLED;
+ INIT_LIST_HEAD(&rc->notifs_chain.list);
+ mutex_init(&rc->notifs_chain.mutex);
+ uwb_drp_avail_init(rc);
+ uwb_rc_ie_init(rc);
+ uwb_rsv_init(rc);
+ uwb_rc_pal_init(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_init);
+
+
+struct uwb_rc *uwb_rc_alloc(void)
+{
+ struct uwb_rc *rc;
+ rc = kzalloc(sizeof(*rc), GFP_KERNEL);
+ if (rc == NULL)
+ return NULL;
+ uwb_rc_init(rc);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_alloc);
+
+static struct attribute *rc_attrs[] = {
+ &dev_attr_mac_address.attr,
+ &dev_attr_scan.attr,
+ &dev_attr_beacon.attr,
+ NULL,
+};
+
+static struct attribute_group rc_attr_group = {
+ .attrs = rc_attrs,
+};
+
+/*
+ * Registration of sysfs specific stuff
+ */
+static int uwb_rc_sys_add(struct uwb_rc *rc)
+{
+ return sysfs_create_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
+}
+
+
+static void __uwb_rc_sys_rm(struct uwb_rc *rc)
+{
+ sysfs_remove_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
+}
+
+/**
+ * uwb_rc_mac_addr_setup - get an RC's EUI-48 address or set it
+ * @rc: the radio controller.
+ *
+ * If the EUI-48 address is 00:00:00:00:00:00 or FF:FF:FF:FF:FF:FF
+ * then a random locally administered EUI-48 is generated and set on
+ * the device. The probability of address collisions is sufficiently
+ * unlikely (1/2^40 = 9.1e-13) that they're not checked for.
+ */
+static
+int uwb_rc_mac_addr_setup(struct uwb_rc *rc)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_dev *uwb_dev = &rc->uwb_dev;
+ char devname[UWB_ADDR_STRSIZE];
+ struct uwb_mac_addr addr;
+
+ result = uwb_rc_mac_addr_get(rc, &addr);
+ if (result < 0) {
+ dev_err(dev, "cannot retrieve UWB EUI-48 address: %d\n", result);
+ return result;
+ }
+
+ if (uwb_mac_addr_unset(&addr) || uwb_mac_addr_bcast(&addr)) {
+ addr.data[0] = 0x02; /* locally adminstered and unicast */
+ get_random_bytes(&addr.data[1], sizeof(addr.data)-1);
+
+ result = uwb_rc_mac_addr_set(rc, &addr);
+ if (result < 0) {
+ uwb_mac_addr_print(devname, sizeof(devname), &addr);
+ dev_err(dev, "cannot set EUI-48 address %s: %d\n",
+ devname, result);
+ return result;
+ }
+ }
+ uwb_dev->mac_addr = addr;
+ return 0;
+}
+
+
+
+static int uwb_rc_setup(struct uwb_rc *rc)
+{
+ int result;
+ struct device *dev = &rc->uwb_dev.dev;
+
+ result = uwb_rc_reset(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot reset UWB radio: %d\n", result);
+ goto error;
+ }
+ result = uwb_rc_mac_addr_setup(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot setup UWB MAC address: %d\n", result);
+ goto error;
+ }
+ result = uwb_rc_dev_addr_assign(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot assign UWB DevAddr: %d\n", result);
+ goto error;
+ }
+ result = uwb_rc_ie_setup(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot setup IE subsystem: %d\n", result);
+ goto error_ie_setup;
+ }
+ result = uwb_rsv_setup(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot setup reservation subsystem: %d\n", result);
+ goto error_rsv_setup;
+ }
+ uwb_dbg_add_rc(rc);
+ return 0;
+
+error_rsv_setup:
+ uwb_rc_ie_release(rc);
+error_ie_setup:
+error:
+ return result;
+}
+
+
+/**
+ * Register a new UWB radio controller
+ *
+ * Did you call uwb_rc_init() on your rc?
+ *
+ * We assume that this is being called with a > 0 refcount on
+ * it [through ops->{get|put}_device(). We'll take our own, though.
+ *
+ * @parent_dev is our real device, the one that provides the actual UWB device
+ */
+int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv)
+{
+ int result;
+ struct device *dev;
+ char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+ rc->index = uwb_rc_new_index();
+
+ dev = &rc->uwb_dev.dev;
+ dev_set_name(dev, "uwb%d", rc->index);
+
+ rc->priv = priv;
+
+ result = rc->start(rc);
+ if (result < 0)
+ goto error_rc_start;
+
+ result = uwb_rc_setup(rc);
+ if (result < 0) {
+ dev_err(dev, "cannot setup UWB radio controller: %d\n", result);
+ goto error_rc_setup;
+ }
+
+ result = uwb_dev_add(&rc->uwb_dev, parent_dev, rc);
+ if (result < 0 && result != -EADDRNOTAVAIL)
+ goto error_dev_add;
+
+ result = uwb_rc_sys_add(rc);
+ if (result < 0) {
+ dev_err(parent_dev, "cannot register UWB radio controller "
+ "dev attributes: %d\n", result);
+ goto error_sys_add;
+ }
+
+ uwb_mac_addr_print(macbuf, sizeof(macbuf), &rc->uwb_dev.mac_addr);
+ uwb_dev_addr_print(devbuf, sizeof(devbuf), &rc->uwb_dev.dev_addr);
+ dev_info(dev,
+ "new uwb radio controller (mac %s dev %s) on %s %s\n",
+ macbuf, devbuf, parent_dev->bus->name, dev_name(parent_dev));
+ rc->ready = 1;
+ return 0;
+
+error_sys_add:
+ uwb_dev_rm(&rc->uwb_dev);
+error_dev_add:
+error_rc_setup:
+ rc->stop(rc);
+ uwbd_flush(rc);
+error_rc_start:
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_add);
+
+
+static int uwb_dev_offair_helper(struct device *dev, void *priv)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+ return __uwb_dev_offair(uwb_dev, uwb_dev->rc);
+}
+
+/*
+ * Remove a Radio Controller; stop beaconing/scanning, disconnect all children
+ */
+void uwb_rc_rm(struct uwb_rc *rc)
+{
+ rc->ready = 0;
+
+ uwb_dbg_del_rc(rc);
+ uwb_rsv_cleanup(rc);
+ uwb_rc_ie_rm(rc, UWB_IDENTIFICATION_IE);
+ if (rc->beaconing >= 0)
+ uwb_rc_beacon(rc, -1, 0);
+ if (rc->scan_type != UWB_SCAN_DISABLED)
+ uwb_rc_scan(rc, rc->scanning, UWB_SCAN_DISABLED, 0);
+ uwb_rc_reset(rc);
+
+ rc->stop(rc);
+ uwbd_flush(rc);
+
+ uwb_dev_lock(&rc->uwb_dev);
+ rc->priv = NULL;
+ rc->cmd = NULL;
+ uwb_dev_unlock(&rc->uwb_dev);
+ mutex_lock(&uwb_beca.mutex);
+ uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL);
+ __uwb_rc_sys_rm(rc);
+ mutex_unlock(&uwb_beca.mutex);
+ uwb_dev_rm(&rc->uwb_dev);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_rm);
+
+static int find_rc_try_get(struct device *dev, void *data)
+{
+ struct uwb_rc *target_rc = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc == NULL) {
+ WARN_ON(1);
+ return 0;
+ }
+ if (rc == target_rc) {
+ if (rc->ready == 0)
+ return 0;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Given a radio controller descriptor, validate and refcount it
+ *
+ * @returns NULL if the rc does not exist or is quiescing; the ptr to
+ * it otherwise.
+ */
+struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *target_rc)
+{
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+ dev = class_find_device(&uwb_rc_class, NULL, target_rc,
+ find_rc_try_get);
+ if (dev) {
+ rc = dev_get_drvdata(dev);
+ __uwb_rc_get(rc);
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(__uwb_rc_try_get);
+
+/*
+ * RC get for external refcount acquirers...
+ *
+ * Increments the refcount of the device and it's backend modules
+ */
+static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc)
+{
+ if (rc->ready == 0)
+ return NULL;
+ uwb_dev_get(&rc->uwb_dev);
+ return rc;
+}
+
+static int find_rc_grandpa(struct device *dev, void *data)
+{
+ struct device *grandpa_dev = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc->uwb_dev.dev.parent->parent == grandpa_dev) {
+ rc = uwb_rc_get(rc);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Locate and refcount a radio controller given a common grand-parent
+ *
+ * @grandpa_dev Pointer to the 'grandparent' device structure.
+ * @returns NULL If the rc does not exist or is quiescing; the ptr to
+ * it otherwise, properly referenced.
+ *
+ * The Radio Control interface (or the UWB Radio Controller) is always
+ * an interface of a device. The parent is the interface, the
+ * grandparent is the device that encapsulates the interface.
+ *
+ * There is no need to lock around as the "grandpa" would be
+ * refcounted by the target, and to remove the referemes, the
+ * uwb_rc_class->sem would have to be taken--we hold it, ergo we
+ * should be safe.
+ */
+struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev)
+{
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+ dev = class_find_device(&uwb_rc_class, NULL, (void *)grandpa_dev,
+ find_rc_grandpa);
+ if (dev)
+ rc = dev_get_drvdata(dev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
+
+/**
+ * Find a radio controller by device address
+ *
+ * @returns the pointer to the radio controller, properly referenced
+ */
+static int find_rc_dev(struct device *dev, void *data)
+{
+ struct uwb_dev_addr *addr = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc == NULL) {
+ WARN_ON(1);
+ return 0;
+ }
+ if (!uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, addr)) {
+ rc = uwb_rc_get(rc);
+ return 1;
+ }
+ return 0;
+}
+
+struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr)
+{
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+ dev = class_find_device(&uwb_rc_class, NULL, (void *)addr,
+ find_rc_dev);
+ if (dev)
+ rc = dev_get_drvdata(dev);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_get_by_dev);
+
+/**
+ * Drop a reference on a radio controller
+ *
+ * This is the version that should be done by entities external to the
+ * UWB Radio Control stack (ie: clients of the API).
+ */
+void uwb_rc_put(struct uwb_rc *rc)
+{
+ __uwb_rc_put(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_put);
+
+/*
+ *
+ *
+ */
+ssize_t uwb_rc_print_IEs(struct uwb_rc *uwb_rc, char *buf, size_t size)
+{
+ ssize_t result;
+ struct uwb_rc_evt_get_ie *ie_info;
+ struct uwb_buf_ctx ctx;
+
+ result = uwb_rc_get_ie(uwb_rc, &ie_info);
+ if (result < 0)
+ goto error_get_ie;
+ ctx.buf = buf;
+ ctx.size = size;
+ ctx.bytes = 0;
+ uwb_ie_for_each(&uwb_rc->uwb_dev, uwb_ie_dump_hex, &ctx,
+ ie_info->IEData, result - sizeof(*ie_info));
+ result = ctx.bytes;
+ kfree(ie_info);
+error_get_ie:
+ return result;
+}
+
diff --git a/drivers/uwb/neh.c b/drivers/uwb/neh.c
new file mode 100644
index 00000000000..9b4eb64327a
--- /dev/null
+++ b/drivers/uwb/neh.c
@@ -0,0 +1,616 @@
+/*
+ * WUSB Wire Adapter: Radio Control Interface (WUSB[8])
+ * Notification and Event Handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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 RC interface of the Host Wire Adapter (USB dongle) or WHCI PCI
+ * card delivers a stream of notifications and events to the
+ * notification end event endpoint or area. This code takes care of
+ * getting a buffer with that data, breaking it up in separate
+ * notifications and events and then deliver those.
+ *
+ * Events are answers to commands and they carry a context ID that
+ * associates them to the command. Notifications are that,
+ * notifications, they come out of the blue and have a context ID of
+ * zero. Think of the context ID kind of like a handler. The
+ * uwb_rc_neh_* code deals with managing context IDs.
+ *
+ * This is why you require a handle to operate on a UWB host. When you
+ * open a handle a context ID is assigned to you.
+ *
+ * So, as it is done is:
+ *
+ * 1. Add an event handler [uwb_rc_neh_add()] (assigns a ctx id)
+ * 2. Issue command [rc->cmd(rc, ...)]
+ * 3. Arm the timeout timer [uwb_rc_neh_arm()]
+ * 4, Release the reference to the neh [uwb_rc_neh_put()]
+ * 5. Wait for the callback
+ * 6. Command result (RCEB) is passed to the callback
+ *
+ * If (2) fails, you should remove the handle [uwb_rc_neh_rm()]
+ * instead of arming the timer.
+ *
+ * Handles are for using in *serialized* code, single thread.
+ *
+ * When the notification/event comes, the IRQ handler/endpoint
+ * callback passes the data read to uwb_rc_neh_grok() which will break
+ * it up in a discrete series of events, look up who is listening for
+ * them and execute the pertinent callbacks.
+ *
+ * If the reader detects an error while reading the data stream, call
+ * uwb_rc_neh_error().
+ *
+ * CONSTRAINTS/ASSUMPTIONS:
+ *
+ * - Most notifications/events are small (less thank .5k), copying
+ * around is ok.
+ *
+ * - Notifications/events are ALWAYS smaller than PAGE_SIZE
+ *
+ * - Notifications/events always come in a single piece (ie: a buffer
+ * will always contain entire notifications/events).
+ *
+ * - we cannot know in advance how long each event is (because they
+ * lack a length field in their header--smart move by the standards
+ * body, btw). So we need a facility to get the event size given the
+ * header. This is what the EST code does (notif/Event Size
+ * Tables), check nest.c--as well, you can associate the size to
+ * the handle [w/ neh->extra_size()].
+ *
+ * - Most notifications/events are fixed size; only a few are variable
+ * size (NEST takes care of that).
+ *
+ * - Listeners of events expect them, so they usually provide a
+ * buffer, as they know the size. Listeners to notifications don't,
+ * so we allocate their buffers dynamically.
+ */
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+
+#include "uwb-internal.h"
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+/*
+ * UWB Radio Controller Notification/Event Handle
+ *
+ * Represents an entity waiting for an event coming from the UWB Radio
+ * Controller with a given context id (context) and type (evt_type and
+ * evt). On reception of the notification/event, the callback (cb) is
+ * called with the event.
+ *
+ * If the timer expires before the event is received, the callback is
+ * called with -ETIMEDOUT as the event size.
+ */
+struct uwb_rc_neh {
+ struct kref kref;
+
+ struct uwb_rc *rc;
+ u8 evt_type;
+ __le16 evt;
+ u8 context;
+ uwb_rc_cmd_cb_f cb;
+ void *arg;
+
+ struct timer_list timer;
+ struct list_head list_node;
+};
+
+static void uwb_rc_neh_timer(unsigned long arg);
+
+static void uwb_rc_neh_release(struct kref *kref)
+{
+ struct uwb_rc_neh *neh = container_of(kref, struct uwb_rc_neh, kref);
+
+ kfree(neh);
+}
+
+static void uwb_rc_neh_get(struct uwb_rc_neh *neh)
+{
+ kref_get(&neh->kref);
+}
+
+/**
+ * uwb_rc_neh_put - release reference to a neh
+ * @neh: the neh
+ */
+void uwb_rc_neh_put(struct uwb_rc_neh *neh)
+{
+ kref_put(&neh->kref, uwb_rc_neh_release);
+}
+
+
+/**
+ * Assigns @neh a context id from @rc's pool
+ *
+ * @rc: UWB Radio Controller descriptor; @rc->neh_lock taken
+ * @neh: Notification/Event Handle
+ * @returns 0 if context id was assigned ok; < 0 errno on error (if
+ * all the context IDs are taken).
+ *
+ * (assumes @wa is locked).
+ *
+ * NOTE: WUSB spec reserves context ids 0x00 for notifications and
+ * 0xff is invalid, so they must not be used. Initialization
+ * fills up those two in the bitmap so they are not allocated.
+ *
+ * We spread the allocation around to reduce the posiblity of two
+ * consecutive opened @neh's getting the same context ID assigned (to
+ * avoid surprises with late events that timed out long time ago). So
+ * first we search from where @rc->ctx_roll is, if not found, we
+ * search from zero.
+ */
+static
+int __uwb_rc_ctx_get(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ int result;
+ result = find_next_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX,
+ rc->ctx_roll++);
+ if (result < UWB_RC_CTX_MAX)
+ goto found;
+ result = find_first_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX);
+ if (result < UWB_RC_CTX_MAX)
+ goto found;
+ return -ENFILE;
+found:
+ set_bit(result, rc->ctx_bm);
+ neh->context = result;
+ return 0;
+}
+
+
+/** Releases @neh's context ID back to @rc (@rc->neh_lock is locked). */
+static
+void __uwb_rc_ctx_put(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ if (neh->context == 0)
+ return;
+ if (test_bit(neh->context, rc->ctx_bm) == 0) {
+ dev_err(dev, "context %u not set in bitmap\n",
+ neh->context);
+ WARN_ON(1);
+ }
+ clear_bit(neh->context, rc->ctx_bm);
+ neh->context = 0;
+}
+
+/**
+ * uwb_rc_neh_add - add a neh for a radio controller command
+ * @rc: the radio controller
+ * @cmd: the radio controller command
+ * @expected_type: the type of the expected response event
+ * @expected_event: the expected event ID
+ * @cb: callback for when the event is received
+ * @arg: argument for the callback
+ *
+ * Creates a neh and adds it to the list of those waiting for an
+ * event. A context ID will be assigned to the command.
+ */
+struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
+ u8 expected_type, u16 expected_event,
+ uwb_rc_cmd_cb_f cb, void *arg)
+{
+ int result;
+ unsigned long flags;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_neh *neh;
+
+ neh = kzalloc(sizeof(*neh), GFP_KERNEL);
+ if (neh == NULL) {
+ result = -ENOMEM;
+ goto error_kzalloc;
+ }
+
+ kref_init(&neh->kref);
+ INIT_LIST_HEAD(&neh->list_node);
+ init_timer(&neh->timer);
+ neh->timer.function = uwb_rc_neh_timer;
+ neh->timer.data = (unsigned long)neh;
+
+ neh->rc = rc;
+ neh->evt_type = expected_type;
+ neh->evt = cpu_to_le16(expected_event);
+ neh->cb = cb;
+ neh->arg = arg;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ result = __uwb_rc_ctx_get(rc, neh);
+ if (result >= 0) {
+ cmd->bCommandContext = neh->context;
+ list_add_tail(&neh->list_node, &rc->neh_list);
+ uwb_rc_neh_get(neh);
+ }
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+ if (result < 0)
+ goto error_ctx_get;
+
+ return neh;
+
+error_ctx_get:
+ kfree(neh);
+error_kzalloc:
+ dev_err(dev, "cannot open handle to radio controller: %d\n", result);
+ return ERR_PTR(result);
+}
+
+static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ del_timer(&neh->timer);
+ __uwb_rc_ctx_put(rc, neh);
+ list_del(&neh->list_node);
+}
+
+/**
+ * uwb_rc_neh_rm - remove a neh.
+ * @rc: the radio controller
+ * @neh: the neh to remove
+ *
+ * Remove an active neh immediately instead of waiting for the event
+ * (or a time out).
+ */
+void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ __uwb_rc_neh_rm(rc, neh);
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+ uwb_rc_neh_put(neh);
+}
+
+/**
+ * uwb_rc_neh_arm - arm an event handler timeout timer
+ *
+ * @rc: UWB Radio Controller
+ * @neh: Notification/event handler for @rc
+ *
+ * The timer is only armed if the neh is active.
+ */
+void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ if (neh->context)
+ mod_timer(&neh->timer,
+ jiffies + msecs_to_jiffies(UWB_RC_CMD_TIMEOUT_MS));
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+}
+
+static void uwb_rc_neh_cb(struct uwb_rc_neh *neh, struct uwb_rceb *rceb, size_t size)
+{
+ (*neh->cb)(neh->rc, neh->arg, rceb, size);
+ uwb_rc_neh_put(neh);
+}
+
+static bool uwb_rc_neh_match(struct uwb_rc_neh *neh, const struct uwb_rceb *rceb)
+{
+ return neh->evt_type == rceb->bEventType
+ && neh->evt == rceb->wEvent
+ && neh->context == rceb->bEventContext;
+}
+
+/**
+ * Find the handle waiting for a RC Radio Control Event
+ *
+ * @rc: UWB Radio Controller
+ * @rceb: Pointer to the RCEB buffer
+ * @event_size: Pointer to the size of the RCEB buffer. Might be
+ * adjusted to take into account the @neh->extra_size
+ * settings.
+ *
+ * If the listener has no buffer (NULL buffer), one is allocated for
+ * the right size (the amount of data received). @neh->ptr will point
+ * to the event payload, which always starts with a 'struct
+ * uwb_rceb'. kfree() it when done.
+ */
+static
+struct uwb_rc_neh *uwb_rc_neh_lookup(struct uwb_rc *rc,
+ const struct uwb_rceb *rceb)
+{
+ struct uwb_rc_neh *neh = NULL, *h;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+
+ list_for_each_entry(h, &rc->neh_list, list_node) {
+ if (uwb_rc_neh_match(h, rceb)) {
+ neh = h;
+ break;
+ }
+ }
+
+ if (neh)
+ __uwb_rc_neh_rm(rc, neh);
+
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+ return neh;
+}
+
+
+/**
+ * Process notifications coming from the radio control interface
+ *
+ * @rc: UWB Radio Control Interface descriptor
+ * @neh: Notification/Event Handler @neh->ptr points to
+ * @uwb_evt->buffer.
+ *
+ * This function is called by the event/notif handling subsystem when
+ * notifications arrive (hwarc_probe() arms a notification/event handle
+ * that calls back this function for every received notification; this
+ * function then will rearm itself).
+ *
+ * Notification data buffers are dynamically allocated by the NEH
+ * handling code in neh.c [uwb_rc_neh_lookup()]. What is actually
+ * allocated is space to contain the notification data.
+ *
+ * Buffers are prefixed with a Radio Control Event Block (RCEB) as
+ * defined by the WUSB Wired-Adapter Radio Control interface. We
+ * just use it for the notification code.
+ *
+ * On each case statement we just transcode endianess of the different
+ * fields. We declare a pointer to a RCI definition of an event, and
+ * then to a UWB definition of the same event (which are the same,
+ * remember). Event if we use different pointers
+ */
+static
+void uwb_rc_notif(struct uwb_rc *rc, struct uwb_rceb *rceb, ssize_t size)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_event *uwb_evt;
+
+ if (size == -ESHUTDOWN)
+ return;
+ if (size < 0) {
+ dev_err(dev, "ignoring event with error code %zu\n",
+ size);
+ return;
+ }
+
+ uwb_evt = kzalloc(sizeof(*uwb_evt), GFP_ATOMIC);
+ if (unlikely(uwb_evt == NULL)) {
+ dev_err(dev, "no memory to queue event 0x%02x/%04x/%02x\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext);
+ return;
+ }
+ uwb_evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */
+ uwb_evt->ts_jiffies = jiffies;
+ uwb_evt->type = UWB_EVT_TYPE_NOTIF;
+ uwb_evt->notif.size = size;
+ uwb_evt->notif.rceb = rceb;
+
+ switch (le16_to_cpu(rceb->wEvent)) {
+ /* Trap some vendor specific events
+ *
+ * FIXME: move this to handling in ptc-est, where we
+ * register a NULL event handler for these two guys
+ * using the Intel IDs.
+ */
+ case 0x0103:
+ dev_info(dev, "FIXME: DEVICE ADD\n");
+ return;
+ case 0x0104:
+ dev_info(dev, "FIXME: DEVICE RM\n");
+ return;
+ default:
+ break;
+ }
+
+ uwbd_event_queue(uwb_evt);
+}
+
+static void uwb_rc_neh_grok_event(struct uwb_rc *rc, struct uwb_rceb *rceb, size_t size)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_neh *neh;
+ struct uwb_rceb *notif;
+
+ if (rceb->bEventContext == 0) {
+ notif = kmalloc(size, GFP_ATOMIC);
+ if (notif) {
+ memcpy(notif, rceb, size);
+ uwb_rc_notif(rc, notif, size);
+ } else
+ dev_err(dev, "event 0x%02x/%04x/%02x (%zu bytes): no memory\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext, size);
+ } else {
+ neh = uwb_rc_neh_lookup(rc, rceb);
+ if (neh)
+ uwb_rc_neh_cb(neh, rceb, size);
+ else
+ dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext, size);
+ }
+}
+
+/**
+ * Given a buffer with one or more UWB RC events/notifications, break
+ * them up and dispatch them.
+ *
+ * @rc: UWB Radio Controller
+ * @buf: Buffer with the stream of notifications/events
+ * @buf_size: Amount of data in the buffer
+ *
+ * Note each notification/event starts always with a 'struct
+ * uwb_rceb', so the minimum size if 4 bytes.
+ *
+ * The device may pass us events formatted differently than expected.
+ * These are first filtered, potentially creating a new event in a new
+ * memory location. If a new event is created by the filter it is also
+ * freed here.
+ *
+ * For each notif/event, tries to guess the size looking at the EST
+ * tables, then looks for a neh that is waiting for that event and if
+ * found, copies the payload to the neh's buffer and calls it back. If
+ * not, the data is ignored.
+ *
+ * Note that if we can't find a size description in the EST tables, we
+ * still might find a size in the 'neh' handle in uwb_rc_neh_lookup().
+ *
+ * Assumptions:
+ *
+ * @rc->neh_lock is NOT taken
+ *
+ * We keep track of various sizes here:
+ * size: contains the size of the buffer that is processed for the
+ * incoming event. this buffer may contain events that are not
+ * formatted as WHCI.
+ * real_size: the actual space taken by this event in the buffer.
+ * We need to keep track of the real size of an event to be able to
+ * advance the buffer correctly.
+ * event_size: the size of the event as expected by the core layer
+ * [OR] the size of the event after filtering. if the filtering
+ * created a new event in a new memory location then this is
+ * effectively the size of a new event buffer
+ */
+void uwb_rc_neh_grok(struct uwb_rc *rc, void *buf, size_t buf_size)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ void *itr;
+ struct uwb_rceb *rceb;
+ size_t size, real_size, event_size;
+ int needtofree;
+
+ d_fnstart(3, dev, "(rc %p buf %p %zu buf_size)\n", rc, buf, buf_size);
+ d_printf(2, dev, "groking event block: %zu bytes\n", buf_size);
+ itr = buf;
+ size = buf_size;
+ while (size > 0) {
+ if (size < sizeof(*rceb)) {
+ dev_err(dev, "not enough data in event buffer to "
+ "process incoming events (%zu left, minimum is "
+ "%zu)\n", size, sizeof(*rceb));
+ break;
+ }
+
+ rceb = itr;
+ if (rc->filter_event) {
+ needtofree = rc->filter_event(rc, &rceb, size,
+ &real_size, &event_size);
+ if (needtofree < 0 && needtofree != -ENOANO) {
+ dev_err(dev, "BUG: Unable to filter event "
+ "(0x%02x/%04x/%02x) from "
+ "device. \n", rceb->bEventType,
+ le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext);
+ break;
+ }
+ } else
+ needtofree = -ENOANO;
+ /* do real processing if there was no filtering or the
+ * filtering didn't act */
+ if (needtofree == -ENOANO) {
+ ssize_t ret = uwb_est_find_size(rc, rceb, size);
+ if (ret < 0)
+ break;
+ if (ret > size) {
+ dev_err(dev, "BUG: hw sent incomplete event "
+ "0x%02x/%04x/%02x (%zd bytes), only got "
+ "%zu bytes. We don't handle that.\n",
+ rceb->bEventType, le16_to_cpu(rceb->wEvent),
+ rceb->bEventContext, ret, size);
+ break;
+ }
+ real_size = event_size = ret;
+ }
+ uwb_rc_neh_grok_event(rc, rceb, event_size);
+
+ if (needtofree == 1)
+ kfree(rceb);
+
+ itr += real_size;
+ size -= real_size;
+ d_printf(2, dev, "consumed %zd bytes, %zu left\n",
+ event_size, size);
+ }
+ d_fnend(3, dev, "(rc %p buf %p %zu buf_size) = void\n", rc, buf, buf_size);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_neh_grok);
+
+
+/**
+ * The entity that reads from the device notification/event channel has
+ * detected an error.
+ *
+ * @rc: UWB Radio Controller
+ * @error: Errno error code
+ *
+ */
+void uwb_rc_neh_error(struct uwb_rc *rc, int error)
+{
+ struct uwb_rc_neh *neh, *next;
+ unsigned long flags;
+
+ BUG_ON(error >= 0);
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ list_for_each_entry_safe(neh, next, &rc->neh_list, list_node) {
+ __uwb_rc_neh_rm(rc, neh);
+ uwb_rc_neh_cb(neh, NULL, error);
+ }
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_neh_error);
+
+
+static void uwb_rc_neh_timer(unsigned long arg)
+{
+ struct uwb_rc_neh *neh = (struct uwb_rc_neh *)arg;
+ struct uwb_rc *rc = neh->rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ __uwb_rc_neh_rm(rc, neh);
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+ uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT);
+}
+
+/** Initializes the @rc's neh subsystem
+ */
+void uwb_rc_neh_create(struct uwb_rc *rc)
+{
+ spin_lock_init(&rc->neh_lock);
+ INIT_LIST_HEAD(&rc->neh_list);
+ set_bit(0, rc->ctx_bm); /* 0 is reserved (see [WUSB] table 8-65) */
+ set_bit(0xff, rc->ctx_bm); /* and 0xff is invalid */
+ rc->ctx_roll = 1;
+}
+
+
+/** Release's the @rc's neh subsystem */
+void uwb_rc_neh_destroy(struct uwb_rc *rc)
+{
+ unsigned long flags;
+ struct uwb_rc_neh *neh, *next;
+
+ spin_lock_irqsave(&rc->neh_lock, flags);
+ list_for_each_entry_safe(neh, next, &rc->neh_list, list_node) {
+ __uwb_rc_neh_rm(rc, neh);
+ uwb_rc_neh_put(neh);
+ }
+ spin_unlock_irqrestore(&rc->neh_lock, flags);
+}
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
new file mode 100644
index 00000000000..1afb38eacb9
--- /dev/null
+++ b/drivers/uwb/pal.c
@@ -0,0 +1,91 @@
+/*
+ * UWB PAL support.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/uwb.h>
+
+#include "uwb-internal.h"
+
+/**
+ * uwb_pal_init - initialize a UWB PAL
+ * @pal: the PAL to initialize
+ */
+void uwb_pal_init(struct uwb_pal *pal)
+{
+ INIT_LIST_HEAD(&pal->node);
+}
+EXPORT_SYMBOL_GPL(uwb_pal_init);
+
+/**
+ * uwb_pal_register - register a UWB PAL
+ * @rc: the radio controller the PAL will be using
+ * @pal: the PAL
+ *
+ * The PAL must be initialized with uwb_pal_init().
+ */
+int uwb_pal_register(struct uwb_rc *rc, struct uwb_pal *pal)
+{
+ int ret;
+
+ if (pal->device) {
+ ret = sysfs_create_link(&pal->device->kobj,
+ &rc->uwb_dev.dev.kobj, "uwb_rc");
+ if (ret < 0)
+ return ret;
+ ret = sysfs_create_link(&rc->uwb_dev.dev.kobj,
+ &pal->device->kobj, pal->name);
+ if (ret < 0) {
+ sysfs_remove_link(&pal->device->kobj, "uwb_rc");
+ return ret;
+ }
+ }
+
+ spin_lock(&rc->pal_lock);
+ list_add(&pal->node, &rc->pals);
+ spin_unlock(&rc->pal_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_pal_register);
+
+/**
+ * uwb_pal_register - unregister a UWB PAL
+ * @rc: the radio controller the PAL was using
+ * @pal: the PAL
+ */
+void uwb_pal_unregister(struct uwb_rc *rc, struct uwb_pal *pal)
+{
+ spin_lock(&rc->pal_lock);
+ list_del(&pal->node);
+ spin_unlock(&rc->pal_lock);
+
+ if (pal->device) {
+ sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+ sysfs_remove_link(&pal->device->kobj, "uwb_rc");
+ }
+}
+EXPORT_SYMBOL_GPL(uwb_pal_unregister);
+
+/**
+ * uwb_rc_pal_init - initialize the PAL related parts of a radio controller
+ * @rc: the radio controller
+ */
+void uwb_rc_pal_init(struct uwb_rc *rc)
+{
+ spin_lock_init(&rc->pal_lock);
+ INIT_LIST_HEAD(&rc->pals);
+}
diff --git a/drivers/uwb/reset.c b/drivers/uwb/reset.c
new file mode 100644
index 00000000000..8de856fa795
--- /dev/null
+++ b/drivers/uwb/reset.c
@@ -0,0 +1,362 @@
+/*
+ * Ultra Wide Band
+ * UWB basic command support and radio reset
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME:
+ *
+ * - docs
+ *
+ * - Now we are serializing (using the uwb_dev->mutex) the command
+ * execution; it should be parallelized as much as possible some
+ * day.
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include "uwb-internal.h"
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+/**
+ * Command result codes (WUSB1.0[T8-69])
+ */
+static
+const char *__strerror[] = {
+ "success",
+ "failure",
+ "hardware failure",
+ "no more slots",
+ "beacon is too large",
+ "invalid parameter",
+ "unsupported power level",
+ "time out (wa) or invalid ie data (whci)",
+ "beacon size exceeded",
+ "cancelled",
+ "invalid state",
+ "invalid size",
+ "ack not recieved",
+ "no more asie notification",
+};
+
+
+/** Return a string matching the given error code */
+const char *uwb_rc_strerror(unsigned code)
+{
+ if (code == 255)
+ return "time out";
+ if (code >= ARRAY_SIZE(__strerror))
+ return "unknown error";
+ return __strerror[code];
+}
+
+int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ u8 expected_type, u16 expected_event,
+ uwb_rc_cmd_cb_f cb, void *arg)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_neh *neh;
+ int needtofree = 0;
+ int result;
+
+ uwb_dev_lock(&rc->uwb_dev); /* Protect against rc->priv being removed */
+ if (rc->priv == NULL) {
+ uwb_dev_unlock(&rc->uwb_dev);
+ return -ESHUTDOWN;
+ }
+
+ if (rc->filter_cmd) {
+ needtofree = rc->filter_cmd(rc, &cmd, &cmd_size);
+ if (needtofree < 0 && needtofree != -ENOANO) {
+ dev_err(dev, "%s: filter error: %d\n",
+ cmd_name, needtofree);
+ uwb_dev_unlock(&rc->uwb_dev);
+ return needtofree;
+ }
+ }
+
+ neh = uwb_rc_neh_add(rc, cmd, expected_type, expected_event, cb, arg);
+ if (IS_ERR(neh)) {
+ result = PTR_ERR(neh);
+ goto out;
+ }
+
+ result = rc->cmd(rc, cmd, cmd_size);
+ uwb_dev_unlock(&rc->uwb_dev);
+ if (result < 0)
+ uwb_rc_neh_rm(rc, neh);
+ else
+ uwb_rc_neh_arm(rc, neh);
+ uwb_rc_neh_put(neh);
+out:
+ if (needtofree == 1)
+ kfree(cmd);
+ return result < 0 ? result : 0;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_cmd_async);
+
+struct uwb_rc_cmd_done_params {
+ struct completion completion;
+ struct uwb_rceb *reply;
+ ssize_t reply_size;
+};
+
+static void uwb_rc_cmd_done(struct uwb_rc *rc, void *arg,
+ struct uwb_rceb *reply, ssize_t reply_size)
+{
+ struct uwb_rc_cmd_done_params *p = (struct uwb_rc_cmd_done_params *)arg;
+
+ if (reply_size > 0) {
+ if (p->reply)
+ reply_size = min(p->reply_size, reply_size);
+ else
+ p->reply = kmalloc(reply_size, GFP_ATOMIC);
+
+ if (p->reply)
+ memcpy(p->reply, reply, reply_size);
+ else
+ reply_size = -ENOMEM;
+ }
+ p->reply_size = reply_size;
+ complete(&p->completion);
+}
+
+
+/**
+ * Generic function for issuing commands to the Radio Control Interface
+ *
+ * @rc: UWB Radio Control descriptor
+ * @cmd_name: Name of the command being issued (for error messages)
+ * @cmd: Pointer to rccb structure containing the command;
+ * normally you embed this structure as the first member of
+ * the full command structure.
+ * @cmd_size: Size of the whole command buffer pointed to by @cmd.
+ * @reply: Pointer to where to store the reply
+ * @reply_size: @reply's size
+ * @expected_type: Expected type in the return event
+ * @expected_event: Expected event code in the return event
+ * @preply: Here a pointer to where the event data is received will
+ * be stored. Once done with the data, free with kfree().
+ *
+ * This function is generic; it works for commands that return a fixed
+ * and known size or for commands that return a variable amount of data.
+ *
+ * If a buffer is provided, that is used, although it could be chopped
+ * to the maximum size of the buffer. If the buffer is NULL, then one
+ * be allocated in *preply with the whole contents of the reply.
+ *
+ * @rc needs to be referenced
+ */
+static
+ssize_t __uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ struct uwb_rceb *reply, size_t reply_size,
+ u8 expected_type, u16 expected_event,
+ struct uwb_rceb **preply)
+{
+ ssize_t result = 0;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_rc_cmd_done_params params;
+
+ init_completion(&params.completion);
+ params.reply = reply;
+ params.reply_size = reply_size;
+
+ result = uwb_rc_cmd_async(rc, cmd_name, cmd, cmd_size,
+ expected_type, expected_event,
+ uwb_rc_cmd_done, &params);
+ if (result)
+ return result;
+
+ wait_for_completion(&params.completion);
+
+ if (preply)
+ *preply = params.reply;
+
+ if (params.reply_size < 0)
+ dev_err(dev, "%s: confirmation event 0x%02x/%04x/%02x "
+ "reception failed: %d\n", cmd_name,
+ expected_type, expected_event, cmd->bCommandContext,
+ (int)params.reply_size);
+ return params.reply_size;
+}
+
+
+/**
+ * Generic function for issuing commands to the Radio Control Interface
+ *
+ * @rc: UWB Radio Control descriptor
+ * @cmd_name: Name of the command being issued (for error messages)
+ * @cmd: Pointer to rccb structure containing the command;
+ * normally you embed this structure as the first member of
+ * the full command structure.
+ * @cmd_size: Size of the whole command buffer pointed to by @cmd.
+ * @reply: Pointer to the beginning of the confirmation event
+ * buffer. Normally bigger than an 'struct hwarc_rceb'.
+ * You need to fill out reply->bEventType and reply->wEvent (in
+ * cpu order) as the function will use them to verify the
+ * confirmation event.
+ * @reply_size: Size of the reply buffer
+ *
+ * The function checks that the length returned in the reply is at
+ * least as big as @reply_size; if not, it will be deemed an error and
+ * -EIO returned.
+ *
+ * @rc needs to be referenced
+ */
+ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ struct uwb_rceb *reply, size_t reply_size)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ ssize_t result;
+
+ result = __uwb_rc_cmd(rc, cmd_name,
+ cmd, cmd_size, reply, reply_size,
+ reply->bEventType, reply->wEvent, NULL);
+
+ if (result > 0 && result < reply_size) {
+ dev_err(dev, "%s: not enough data returned for decoding reply "
+ "(%zu bytes received vs at least %zu needed)\n",
+ cmd_name, result, reply_size);
+ result = -EIO;
+ }
+ return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_cmd);
+
+
+/**
+ * Generic function for issuing commands to the Radio Control
+ * Interface that return an unknown amount of data
+ *
+ * @rc: UWB Radio Control descriptor
+ * @cmd_name: Name of the command being issued (for error messages)
+ * @cmd: Pointer to rccb structure containing the command;
+ * normally you embed this structure as the first member of
+ * the full command structure.
+ * @cmd_size: Size of the whole command buffer pointed to by @cmd.
+ * @expected_type: Expected type in the return event
+ * @expected_event: Expected event code in the return event
+ * @preply: Here a pointer to where the event data is received will
+ * be stored. Once done with the data, free with kfree().
+ *
+ * The function checks that the length returned in the reply is at
+ * least as big as a 'struct uwb_rceb *'; if not, it will be deemed an
+ * error and -EIO returned.
+ *
+ * @rc needs to be referenced
+ */
+ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
+ struct uwb_rccb *cmd, size_t cmd_size,
+ u8 expected_type, u16 expected_event,
+ struct uwb_rceb **preply)
+{
+ return __uwb_rc_cmd(rc, cmd_name, cmd, cmd_size, NULL, 0,
+ expected_type, expected_event, preply);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_vcmd);
+
+
+/**
+ * Reset a UWB Host Controller (and all radio settings)
+ *
+ * @rc: Host Controller descriptor
+ * @returns: 0 if ok, < 0 errno code on error
+ *
+ * We put the command on kmalloc'ed memory as some arches cannot do
+ * USB from the stack. The reply event is copied from an stage buffer,
+ * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
+ */
+int uwb_rc_reset(struct uwb_rc *rc)
+{
+ int result = -ENOMEM;
+ struct uwb_rc_evt_confirm reply;
+ struct uwb_rccb *cmd;
+ size_t cmd_size = sizeof(*cmd);
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_kzalloc;
+ cmd->bCommandType = UWB_RC_CET_GENERAL;
+ cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_RESET;
+ result = uwb_rc_cmd(rc, "RESET", cmd, cmd_size,
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "RESET: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ }
+error_cmd:
+ kfree(cmd);
+error_kzalloc:
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+int uwbd_msg_handle_reset(struct uwb_event *evt)
+{
+ struct uwb_rc *rc = evt->rc;
+ int ret;
+
+ /* Need to prevent the RC hardware module going away while in
+ the rc->reset() call. */
+ if (!try_module_get(rc->owner))
+ return 0;
+
+ dev_info(&rc->uwb_dev.dev, "resetting radio controller\n");
+ ret = rc->reset(rc);
+ if (ret)
+ dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret);
+
+ module_put(rc->owner);
+ return ret;
+}
+
+/**
+ * uwb_rc_reset_all - request a reset of the radio controller and PALs
+ * @rc: the radio controller of the hardware device to be reset.
+ *
+ * The full hardware reset of the radio controller and all the PALs
+ * will be scheduled.
+ */
+void uwb_rc_reset_all(struct uwb_rc *rc)
+{
+ struct uwb_event *evt;
+
+ evt = kzalloc(sizeof(struct uwb_event), GFP_ATOMIC);
+ if (unlikely(evt == NULL))
+ return;
+
+ evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */
+ evt->ts_jiffies = jiffies;
+ evt->type = UWB_EVT_TYPE_MSG;
+ evt->message = UWB_EVT_MSG_RESET;
+
+ uwbd_event_queue(evt);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_reset_all);
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c
new file mode 100644
index 00000000000..bae16204576
--- /dev/null
+++ b/drivers/uwb/rsv.c
@@ -0,0 +1,680 @@
+/*
+ * UWB reservation management.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/uwb.h>
+
+#include "uwb-internal.h"
+
+static void uwb_rsv_timer(unsigned long arg);
+
+static const char *rsv_states[] = {
+ [UWB_RSV_STATE_NONE] = "none",
+ [UWB_RSV_STATE_O_INITIATED] = "initiated",
+ [UWB_RSV_STATE_O_PENDING] = "pending",
+ [UWB_RSV_STATE_O_MODIFIED] = "modified",
+ [UWB_RSV_STATE_O_ESTABLISHED] = "established",
+ [UWB_RSV_STATE_T_ACCEPTED] = "accepted",
+ [UWB_RSV_STATE_T_DENIED] = "denied",
+ [UWB_RSV_STATE_T_PENDING] = "pending",
+};
+
+static const char *rsv_types[] = {
+ [UWB_DRP_TYPE_ALIEN_BP] = "alien-bp",
+ [UWB_DRP_TYPE_HARD] = "hard",
+ [UWB_DRP_TYPE_SOFT] = "soft",
+ [UWB_DRP_TYPE_PRIVATE] = "private",
+ [UWB_DRP_TYPE_PCA] = "pca",
+};
+
+/**
+ * uwb_rsv_state_str - return a string for a reservation state
+ * @state: the reservation state.
+ */
+const char *uwb_rsv_state_str(enum uwb_rsv_state state)
+{
+ if (state < UWB_RSV_STATE_NONE || state >= UWB_RSV_STATE_LAST)
+ return "unknown";
+ return rsv_states[state];
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_state_str);
+
+/**
+ * uwb_rsv_type_str - return a string for a reservation type
+ * @type: the reservation type
+ */
+const char *uwb_rsv_type_str(enum uwb_drp_type type)
+{
+ if (type < UWB_DRP_TYPE_ALIEN_BP || type > UWB_DRP_TYPE_PCA)
+ return "invalid";
+ return rsv_types[type];
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_type_str);
+
+static void uwb_rsv_dump(struct uwb_rsv *rsv)
+{
+ struct device *dev = &rsv->rc->uwb_dev.dev;
+ struct uwb_dev_addr devaddr;
+ char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
+
+ uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
+ if (rsv->target.type == UWB_RSV_TARGET_DEV)
+ devaddr = rsv->target.dev->dev_addr;
+ else
+ devaddr = rsv->target.devaddr;
+ uwb_dev_addr_print(target, sizeof(target), &devaddr);
+
+ dev_dbg(dev, "rsv %s -> %s: %s\n", owner, target, uwb_rsv_state_str(rsv->state));
+}
+
+/*
+ * Get a free stream index for a reservation.
+ *
+ * If the target is a DevAddr (e.g., a WUSB cluster reservation) then
+ * the stream is allocated from a pool of per-RC stream indexes,
+ * otherwise a unique stream index for the target is selected.
+ */
+static int uwb_rsv_get_stream(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+ unsigned long *streams_bm;
+ int stream;
+
+ switch (rsv->target.type) {
+ case UWB_RSV_TARGET_DEV:
+ streams_bm = rsv->target.dev->streams;
+ break;
+ case UWB_RSV_TARGET_DEVADDR:
+ streams_bm = rc->uwb_dev.streams;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ stream = find_first_zero_bit(streams_bm, UWB_NUM_STREAMS);
+ if (stream >= UWB_NUM_STREAMS)
+ return -EBUSY;
+
+ rsv->stream = stream;
+ set_bit(stream, streams_bm);
+
+ return 0;
+}
+
+static void uwb_rsv_put_stream(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+ unsigned long *streams_bm;
+
+ switch (rsv->target.type) {
+ case UWB_RSV_TARGET_DEV:
+ streams_bm = rsv->target.dev->streams;
+ break;
+ case UWB_RSV_TARGET_DEVADDR:
+ streams_bm = rc->uwb_dev.streams;
+ break;
+ default:
+ return;
+ }
+
+ clear_bit(rsv->stream, streams_bm);
+}
+
+/*
+ * Generate a MAS allocation with a single row component.
+ */
+static void uwb_rsv_gen_alloc_row(struct uwb_mas_bm *mas,
+ int first_mas, int mas_per_zone,
+ int zs, int ze)
+{
+ struct uwb_mas_bm col;
+ int z;
+
+ bitmap_zero(mas->bm, UWB_NUM_MAS);
+ bitmap_zero(col.bm, UWB_NUM_MAS);
+ bitmap_fill(col.bm, mas_per_zone);
+ bitmap_shift_left(col.bm, col.bm, first_mas + zs * UWB_MAS_PER_ZONE, UWB_NUM_MAS);
+
+ for (z = zs; z <= ze; z++) {
+ bitmap_or(mas->bm, mas->bm, col.bm, UWB_NUM_MAS);
+ bitmap_shift_left(col.bm, col.bm, UWB_MAS_PER_ZONE, UWB_NUM_MAS);
+ }
+}
+
+/*
+ * Allocate some MAS for this reservation based on current local
+ * availability, the reservation parameters (max_mas, min_mas,
+ * sparsity), and the WiMedia rules for MAS allocations.
+ *
+ * Returns -EBUSY is insufficient free MAS are available.
+ *
+ * FIXME: to simplify this, only safe reservations with a single row
+ * component in zones 1 to 15 are tried (zone 0 is skipped to avoid
+ * problems with the MAS reserved for the BP).
+ *
+ * [ECMA-368] section B.2.
+ */
+static int uwb_rsv_alloc_mas(struct uwb_rsv *rsv)
+{
+ static const int safe_mas_in_row[UWB_NUM_ZONES] = {
+ 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1,
+ };
+ int n, r;
+ struct uwb_mas_bm mas;
+ bool found = false;
+
+ /*
+ * Search all valid safe allocations until either: too few MAS
+ * are available; or the smallest allocation with sufficient
+ * MAS is found.
+ *
+ * The top of the zones are preferred, so space for larger
+ * allocations is available in the bottom of the zone (e.g., a
+ * 15 MAS allocation should start in row 14 leaving space for
+ * a 120 MAS allocation at row 0).
+ */
+ for (n = safe_mas_in_row[0]; n >= 1; n--) {
+ int num_mas;
+
+ num_mas = n * (UWB_NUM_ZONES - 1);
+ if (num_mas < rsv->min_mas)
+ break;
+ if (found && num_mas < rsv->max_mas)
+ break;
+
+ for (r = UWB_MAS_PER_ZONE-1; r >= 0; r--) {
+ if (safe_mas_in_row[r] < n)
+ continue;
+ uwb_rsv_gen_alloc_row(&mas, r, n, 1, UWB_NUM_ZONES);
+ if (uwb_drp_avail_reserve_pending(rsv->rc, &mas) == 0) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ return -EBUSY;
+
+ bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS);
+ return 0;
+}
+
+static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv)
+{
+ int sframes = UWB_MAX_LOST_BEACONS;
+
+ /*
+ * Multicast reservations can become established within 1
+ * super frame and should not be terminated if no response is
+ * received.
+ */
+ if (rsv->is_multicast) {
+ if (rsv->state == UWB_RSV_STATE_O_INITIATED)
+ sframes = 1;
+ if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED)
+ sframes = 0;
+ }
+
+ rsv->expired = false;
+ if (sframes > 0) {
+ /*
+ * Add an additional 2 superframes to account for the
+ * time to send the SET DRP IE command.
+ */
+ unsigned timeout_us = (sframes + 2) * UWB_SUPERFRAME_LENGTH_US;
+ mod_timer(&rsv->timer, jiffies + usecs_to_jiffies(timeout_us));
+ } else
+ del_timer(&rsv->timer);
+}
+
+/*
+ * Update a reservations state, and schedule an update of the
+ * transmitted DRP IEs.
+ */
+static void uwb_rsv_state_update(struct uwb_rsv *rsv,
+ enum uwb_rsv_state new_state)
+{
+ rsv->state = new_state;
+ rsv->ie_valid = false;
+
+ uwb_rsv_dump(rsv);
+
+ uwb_rsv_stroke_timer(rsv);
+ uwb_rsv_sched_update(rsv->rc);
+}
+
+static void uwb_rsv_callback(struct uwb_rsv *rsv)
+{
+ if (rsv->callback)
+ rsv->callback(rsv);
+}
+
+void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state)
+{
+ if (rsv->state == new_state) {
+ switch (rsv->state) {
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ case UWB_RSV_STATE_T_ACCEPTED:
+ case UWB_RSV_STATE_NONE:
+ uwb_rsv_stroke_timer(rsv);
+ break;
+ default:
+ /* Expecting a state transition so leave timer
+ as-is. */
+ break;
+ }
+ return;
+ }
+
+ switch (new_state) {
+ case UWB_RSV_STATE_NONE:
+ uwb_drp_avail_release(rsv->rc, &rsv->mas);
+ uwb_rsv_put_stream(rsv);
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE);
+ uwb_rsv_callback(rsv);
+ break;
+ case UWB_RSV_STATE_O_INITIATED:
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_INITIATED);
+ break;
+ case UWB_RSV_STATE_O_PENDING:
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING);
+ break;
+ case UWB_RSV_STATE_O_ESTABLISHED:
+ uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+ uwb_rsv_callback(rsv);
+ break;
+ case UWB_RSV_STATE_T_ACCEPTED:
+ uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED);
+ uwb_rsv_callback(rsv);
+ break;
+ case UWB_RSV_STATE_T_DENIED:
+ uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED);
+ break;
+ default:
+ dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n",
+ uwb_rsv_state_str(new_state), new_state);
+ }
+}
+
+static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc)
+{
+ struct uwb_rsv *rsv;
+
+ rsv = kzalloc(sizeof(struct uwb_rsv), GFP_KERNEL);
+ if (!rsv)
+ return NULL;
+
+ INIT_LIST_HEAD(&rsv->rc_node);
+ INIT_LIST_HEAD(&rsv->pal_node);
+ init_timer(&rsv->timer);
+ rsv->timer.function = uwb_rsv_timer;
+ rsv->timer.data = (unsigned long)rsv;
+
+ rsv->rc = rc;
+
+ return rsv;
+}
+
+static void uwb_rsv_free(struct uwb_rsv *rsv)
+{
+ uwb_dev_put(rsv->owner);
+ if (rsv->target.type == UWB_RSV_TARGET_DEV)
+ uwb_dev_put(rsv->target.dev);
+ kfree(rsv);
+}
+
+/**
+ * uwb_rsv_create - allocate and initialize a UWB reservation structure
+ * @rc: the radio controller
+ * @cb: callback to use when the reservation completes or terminates
+ * @pal_priv: data private to the PAL to be passed in the callback
+ *
+ * The callback is called when the state of the reservation changes from:
+ *
+ * - pending to accepted
+ * - pending to denined
+ * - accepted to terminated
+ * - pending to terminated
+ */
+struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, void *pal_priv)
+{
+ struct uwb_rsv *rsv;
+
+ rsv = uwb_rsv_alloc(rc);
+ if (!rsv)
+ return NULL;
+
+ rsv->callback = cb;
+ rsv->pal_priv = pal_priv;
+
+ return rsv;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_create);
+
+void uwb_rsv_remove(struct uwb_rsv *rsv)
+{
+ if (rsv->state != UWB_RSV_STATE_NONE)
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+ del_timer_sync(&rsv->timer);
+ list_del(&rsv->rc_node);
+ uwb_rsv_free(rsv);
+}
+
+/**
+ * uwb_rsv_destroy - free a UWB reservation structure
+ * @rsv: the reservation to free
+ *
+ * The reservation will be terminated if it is pending or established.
+ */
+void uwb_rsv_destroy(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+
+ mutex_lock(&rc->rsvs_mutex);
+ uwb_rsv_remove(rsv);
+ mutex_unlock(&rc->rsvs_mutex);
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_destroy);
+
+/**
+ * usb_rsv_establish - start a reservation establishment
+ * @rsv: the reservation
+ *
+ * The PAL should fill in @rsv's owner, target, type, max_mas,
+ * min_mas, sparsity and is_multicast fields. If the target is a
+ * uwb_dev it must be referenced.
+ *
+ * The reservation's callback will be called when the reservation is
+ * accepted, denied or times out.
+ */
+int uwb_rsv_establish(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+ int ret;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ ret = uwb_rsv_get_stream(rsv);
+ if (ret)
+ goto out;
+
+ ret = uwb_rsv_alloc_mas(rsv);
+ if (ret) {
+ uwb_rsv_put_stream(rsv);
+ goto out;
+ }
+
+ list_add_tail(&rsv->rc_node, &rc->reservations);
+ rsv->owner = &rc->uwb_dev;
+ uwb_dev_get(rsv->owner);
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_INITIATED);
+out:
+ mutex_unlock(&rc->rsvs_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_establish);
+
+/**
+ * uwb_rsv_modify - modify an already established reservation
+ * @rsv: the reservation to modify
+ * @max_mas: new maximum MAS to reserve
+ * @min_mas: new minimum MAS to reserve
+ * @sparsity: new sparsity to use
+ *
+ * FIXME: implement this once there are PALs that use it.
+ */
+int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int sparsity)
+{
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_modify);
+
+/**
+ * uwb_rsv_terminate - terminate an established reservation
+ * @rsv: the reservation to terminate
+ *
+ * A reservation is terminated by removing the DRP IE from the beacon,
+ * the other end will consider the reservation to be terminated when
+ * it does not see the DRP IE for at least mMaxLostBeacons.
+ *
+ * If applicable, the reference to the target uwb_dev will be released.
+ */
+void uwb_rsv_terminate(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+
+ mutex_unlock(&rc->rsvs_mutex);
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_terminate);
+
+/**
+ * uwb_rsv_accept - accept a new reservation from a peer
+ * @rsv: the reservation
+ * @cb: call back for reservation changes
+ * @pal_priv: data to be passed in the above call back
+ *
+ * Reservation requests from peers are denied unless a PAL accepts it
+ * by calling this function.
+ */
+void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv)
+{
+ rsv->callback = cb;
+ rsv->pal_priv = pal_priv;
+ rsv->state = UWB_RSV_STATE_T_ACCEPTED;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_accept);
+
+/*
+ * Is a received DRP IE for this reservation?
+ */
+static bool uwb_rsv_match(struct uwb_rsv *rsv, struct uwb_dev *src,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct uwb_dev_addr *rsv_src;
+ int stream;
+
+ stream = uwb_ie_drp_stream_index(drp_ie);
+
+ if (rsv->stream != stream)
+ return false;
+
+ switch (rsv->target.type) {
+ case UWB_RSV_TARGET_DEVADDR:
+ return rsv->stream == stream;
+ case UWB_RSV_TARGET_DEV:
+ if (uwb_ie_drp_owner(drp_ie))
+ rsv_src = &rsv->owner->dev_addr;
+ else
+ rsv_src = &rsv->target.dev->dev_addr;
+ return uwb_dev_addr_cmp(&src->dev_addr, rsv_src) == 0;
+ }
+ return false;
+}
+
+static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc,
+ struct uwb_dev *src,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct uwb_rsv *rsv;
+ struct uwb_pal *pal;
+ enum uwb_rsv_state state;
+
+ rsv = uwb_rsv_alloc(rc);
+ if (!rsv)
+ return NULL;
+
+ rsv->rc = rc;
+ rsv->owner = src;
+ uwb_dev_get(rsv->owner);
+ rsv->target.type = UWB_RSV_TARGET_DEV;
+ rsv->target.dev = &rc->uwb_dev;
+ rsv->type = uwb_ie_drp_type(drp_ie);
+ rsv->stream = uwb_ie_drp_stream_index(drp_ie);
+ set_bit(rsv->stream, rsv->owner->streams);
+ uwb_drp_ie_to_bm(&rsv->mas, drp_ie);
+
+ /*
+ * See if any PALs are interested in this reservation. If not,
+ * deny the request.
+ */
+ rsv->state = UWB_RSV_STATE_T_DENIED;
+ spin_lock(&rc->pal_lock);
+ list_for_each_entry(pal, &rc->pals, node) {
+ if (pal->new_rsv)
+ pal->new_rsv(rsv);
+ if (rsv->state == UWB_RSV_STATE_T_ACCEPTED)
+ break;
+ }
+ spin_unlock(&rc->pal_lock);
+
+ list_add_tail(&rsv->rc_node, &rc->reservations);
+ state = rsv->state;
+ rsv->state = UWB_RSV_STATE_NONE;
+ uwb_rsv_set_state(rsv, state);
+
+ return rsv;
+}
+
+/**
+ * uwb_rsv_find - find a reservation for a received DRP IE.
+ * @rc: the radio controller
+ * @src: source of the DRP IE
+ * @drp_ie: the DRP IE
+ *
+ * If the reservation cannot be found and the DRP IE is from a peer
+ * attempting to establish a new reservation, create a new reservation
+ * and add it to the list.
+ */
+struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
+ struct uwb_ie_drp *drp_ie)
+{
+ struct uwb_rsv *rsv;
+
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ if (uwb_rsv_match(rsv, src, drp_ie))
+ return rsv;
+ }
+
+ if (uwb_ie_drp_owner(drp_ie))
+ return uwb_rsv_new_target(rc, src, drp_ie);
+
+ return NULL;
+}
+
+/*
+ * Go through all the reservations and check for timeouts and (if
+ * necessary) update their DRP IEs.
+ *
+ * FIXME: look at building the SET_DRP_IE command here rather than
+ * having to rescan the list in uwb_rc_send_all_drp_ie().
+ */
+static bool uwb_rsv_update_all(struct uwb_rc *rc)
+{
+ struct uwb_rsv *rsv, *t;
+ bool ie_updated = false;
+
+ list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
+ if (rsv->expired)
+ uwb_drp_handle_timeout(rsv);
+ if (!rsv->ie_valid) {
+ uwb_drp_ie_update(rsv);
+ ie_updated = true;
+ }
+ }
+
+ return ie_updated;
+}
+
+void uwb_rsv_sched_update(struct uwb_rc *rc)
+{
+ queue_work(rc->rsv_workq, &rc->rsv_update_work);
+}
+
+/*
+ * Update DRP IEs and, if necessary, the DRP Availability IE and send
+ * the updated IEs to the radio controller.
+ */
+static void uwb_rsv_update_work(struct work_struct *work)
+{
+ struct uwb_rc *rc = container_of(work, struct uwb_rc, rsv_update_work);
+ bool ie_updated;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ ie_updated = uwb_rsv_update_all(rc);
+
+ if (!rc->drp_avail.ie_valid) {
+ uwb_drp_avail_ie_update(rc);
+ ie_updated = true;
+ }
+
+ if (ie_updated)
+ uwb_rc_send_all_drp_ie(rc);
+
+ mutex_unlock(&rc->rsvs_mutex);
+}
+
+static void uwb_rsv_timer(unsigned long arg)
+{
+ struct uwb_rsv *rsv = (struct uwb_rsv *)arg;
+
+ rsv->expired = true;
+ uwb_rsv_sched_update(rsv->rc);
+}
+
+void uwb_rsv_init(struct uwb_rc *rc)
+{
+ INIT_LIST_HEAD(&rc->reservations);
+ mutex_init(&rc->rsvs_mutex);
+ INIT_WORK(&rc->rsv_update_work, uwb_rsv_update_work);
+
+ bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS);
+}
+
+int uwb_rsv_setup(struct uwb_rc *rc)
+{
+ char name[16];
+
+ snprintf(name, sizeof(name), "%s_rsvd", dev_name(&rc->uwb_dev.dev));
+ rc->rsv_workq = create_singlethread_workqueue(name);
+ if (rc->rsv_workq == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void uwb_rsv_cleanup(struct uwb_rc *rc)
+{
+ struct uwb_rsv *rsv, *t;
+
+ mutex_lock(&rc->rsvs_mutex);
+ list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
+ uwb_rsv_remove(rsv);
+ }
+ mutex_unlock(&rc->rsvs_mutex);
+
+ cancel_work_sync(&rc->rsv_update_work);
+ destroy_workqueue(rc->rsv_workq);
+}
diff --git a/drivers/uwb/scan.c b/drivers/uwb/scan.c
new file mode 100644
index 00000000000..2d270748f32
--- /dev/null
+++ b/drivers/uwb/scan.c
@@ -0,0 +1,133 @@
+/*
+ * Ultra Wide Band
+ * Scanning management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ *
+ * FIXME: docs
+ * FIXME: there are issues here on how BEACON and SCAN on USB RCI deal
+ * with each other. Currently seems that START_BEACON while
+ * SCAN_ONLY will cancel the scan, so we need to update the
+ * state here. Clarification request sent by email on
+ * 10/05/2005.
+ * 10/28/2005 No clear answer heard--maybe we'll hack the API
+ * so that when we start beaconing, if the HC is
+ * scanning in a mode not compatible with beaconing
+ * we just fail.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include "uwb-internal.h"
+
+
+/**
+ * Start/stop scanning in a radio controller
+ *
+ * @rc: UWB Radio Controlller
+ * @channel: Channel to scan; encodings in WUSB1.0[Table 5.12]
+ * @type: Type of scanning to do.
+ * @bpst_offset: value at which to start scanning (if type ==
+ * UWB_SCAN_ONLY_STARTTIME)
+ * @returns: 0 if ok, < 0 errno code on error
+ *
+ * We put the command on kmalloc'ed memory as some arches cannot do
+ * USB from the stack. The reply event is copied from an stage buffer,
+ * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
+ */
+int uwb_rc_scan(struct uwb_rc *rc,
+ unsigned channel, enum uwb_scan_type type,
+ unsigned bpst_offset)
+{
+ int result;
+ struct uwb_rc_cmd_scan *cmd;
+ struct uwb_rc_evt_confirm reply;
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_kzalloc;
+ mutex_lock(&rc->uwb_dev.mutex);
+ cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+ cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SCAN);
+ cmd->bChannelNumber = channel;
+ cmd->bScanState = type;
+ cmd->wStartTime = cpu_to_le16(bpst_offset);
+ reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+ reply.rceb.wEvent = UWB_RC_CMD_SCAN;
+ result = uwb_rc_cmd(rc, "SCAN", &cmd->rccb, sizeof(*cmd),
+ &reply.rceb, sizeof(reply));
+ if (result < 0)
+ goto error_cmd;
+ if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+ dev_err(&rc->uwb_dev.dev,
+ "SCAN: command execution failed: %s (%d)\n",
+ uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+ result = -EIO;
+ goto error_cmd;
+ }
+ rc->scanning = channel;
+ rc->scan_type = type;
+error_cmd:
+ mutex_unlock(&rc->uwb_dev.mutex);
+ kfree(cmd);
+error_kzalloc:
+ return result;
+}
+
+/*
+ * Print scanning state
+ */
+static ssize_t uwb_rc_scan_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ ssize_t result;
+
+ mutex_lock(&rc->uwb_dev.mutex);
+ result = sprintf(buf, "%d %d\n", rc->scanning, rc->scan_type);
+ mutex_unlock(&rc->uwb_dev.mutex);
+ return result;
+}
+
+/*
+ *
+ */
+static ssize_t uwb_rc_scan_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+ struct uwb_rc *rc = uwb_dev->rc;
+ unsigned channel;
+ unsigned type;
+ unsigned bpst_offset = 0;
+ ssize_t result = -EINVAL;
+
+ result = sscanf(buf, "%u %u %u\n", &channel, &type, &bpst_offset);
+ if (result >= 2 && type < UWB_SCAN_TOP)
+ result = uwb_rc_scan(rc, channel, type, bpst_offset);
+
+ return result < 0 ? result : size;
+}
+
+/** Radio Control sysfs interface (declaration) */
+DEVICE_ATTR(scan, S_IRUGO | S_IWUSR, uwb_rc_scan_show, uwb_rc_scan_store);
diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c
new file mode 100644
index 00000000000..2d8d62d9f53
--- /dev/null
+++ b/drivers/uwb/umc-bus.c
@@ -0,0 +1,218 @@
+/*
+ * Bus for UWB Multi-interface Controller capabilities.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * This file is released under the GNU GPL v2.
+ */
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+#include <linux/uwb/umc.h>
+#include <linux/pci.h>
+
+static int umc_bus_unbind_helper(struct device *dev, void *data)
+{
+ struct device *parent = data;
+
+ if (dev->parent == parent && dev->driver)
+ device_release_driver(dev);
+ return 0;
+}
+
+/**
+ * umc_controller_reset - reset the whole UMC controller
+ * @umc: the UMC device for the radio controller.
+ *
+ * Drivers will be unbound from all UMC devices belonging to the
+ * controller and then the radio controller will be rebound. The
+ * radio controller is expected to do a full hardware reset when it is
+ * probed.
+ *
+ * If this is called while a probe() or remove() is in progress it
+ * will return -EAGAIN and not perform the reset.
+ */
+int umc_controller_reset(struct umc_dev *umc)
+{
+ struct device *parent = umc->dev.parent;
+ int ret;
+
+ if (down_trylock(&parent->sem))
+ return -EAGAIN;
+ bus_for_each_dev(&umc_bus_type, NULL, parent, umc_bus_unbind_helper);
+ ret = device_attach(&umc->dev);
+ if (ret == 1)
+ ret = 0;
+ up(&parent->sem);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(umc_controller_reset);
+
+/**
+ * umc_match_pci_id - match a UMC driver to a UMC device's parent PCI device.
+ * @umc_drv: umc driver with match_data pointing to a zero-terminated
+ * table of pci_device_id's.
+ * @umc: umc device whose parent is to be matched.
+ */
+int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc)
+{
+ const struct pci_device_id *id_table = umc_drv->match_data;
+ struct pci_dev *pci;
+
+ if (umc->dev.parent->bus != &pci_bus_type)
+ return 0;
+
+ pci = to_pci_dev(umc->dev.parent);
+ return pci_match_id(id_table, pci) != NULL;
+}
+EXPORT_SYMBOL_GPL(umc_match_pci_id);
+
+static int umc_bus_rescan_helper(struct device *dev, void *data)
+{
+ int ret = 0;
+
+ if (!dev->driver)
+ ret = device_attach(dev);
+
+ return ret < 0 ? ret : 0;
+}
+
+static void umc_bus_rescan(void)
+{
+ int err;
+
+ /*
+ * We can't use bus_rescan_devices() here as it deadlocks when
+ * it tries to retake the dev->parent semaphore.
+ */
+ err = bus_for_each_dev(&umc_bus_type, NULL, NULL, umc_bus_rescan_helper);
+ if (err < 0)
+ printk(KERN_WARNING "%s: rescan of bus failed: %d\n",
+ KBUILD_MODNAME, err);
+}
+
+static int umc_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct umc_dev *umc = to_umc_dev(dev);
+ struct umc_driver *umc_driver = to_umc_driver(drv);
+
+ if (umc->cap_id == umc_driver->cap_id) {
+ if (umc_driver->match)
+ return umc_driver->match(umc_driver, umc);
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int umc_device_probe(struct device *dev)
+{
+ struct umc_dev *umc;
+ struct umc_driver *umc_driver;
+ int err;
+
+ umc_driver = to_umc_driver(dev->driver);
+ umc = to_umc_dev(dev);
+
+ get_device(dev);
+ err = umc_driver->probe(umc);
+ if (err)
+ put_device(dev);
+ else
+ umc_bus_rescan();
+
+ return err;
+}
+
+static int umc_device_remove(struct device *dev)
+{
+ struct umc_dev *umc;
+ struct umc_driver *umc_driver;
+
+ umc_driver = to_umc_driver(dev->driver);
+ umc = to_umc_dev(dev);
+
+ umc_driver->remove(umc);
+ put_device(dev);
+ return 0;
+}
+
+static int umc_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct umc_dev *umc;
+ struct umc_driver *umc_driver;
+ int err = 0;
+
+ umc = to_umc_dev(dev);
+
+ if (dev->driver) {
+ umc_driver = to_umc_driver(dev->driver);
+ if (umc_driver->suspend)
+ err = umc_driver->suspend(umc, state);
+ }
+ return err;
+}
+
+static int umc_device_resume(struct device *dev)
+{
+ struct umc_dev *umc;
+ struct umc_driver *umc_driver;
+ int err = 0;
+
+ umc = to_umc_dev(dev);
+
+ if (dev->driver) {
+ umc_driver = to_umc_driver(dev->driver);
+ if (umc_driver->resume)
+ err = umc_driver->resume(umc);
+ }
+ return err;
+}
+
+static ssize_t capability_id_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct umc_dev *umc = to_umc_dev(dev);
+
+ return sprintf(buf, "0x%02x\n", umc->cap_id);
+}
+
+static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct umc_dev *umc = to_umc_dev(dev);
+
+ return sprintf(buf, "0x%04x\n", umc->version);
+}
+
+static struct device_attribute umc_dev_attrs[] = {
+ __ATTR_RO(capability_id),
+ __ATTR_RO(version),
+ __ATTR_NULL,
+};
+
+struct bus_type umc_bus_type = {
+ .name = "umc",
+ .match = umc_bus_match,
+ .probe = umc_device_probe,
+ .remove = umc_device_remove,
+ .suspend = umc_device_suspend,
+ .resume = umc_device_resume,
+ .dev_attrs = umc_dev_attrs,
+};
+EXPORT_SYMBOL_GPL(umc_bus_type);
+
+static int __init umc_bus_init(void)
+{
+ return bus_register(&umc_bus_type);
+}
+module_init(umc_bus_init);
+
+static void __exit umc_bus_exit(void)
+{
+ bus_unregister(&umc_bus_type);
+}
+module_exit(umc_bus_exit);
+
+MODULE_DESCRIPTION("UWB Multi-interface Controller capability bus");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/umc-dev.c b/drivers/uwb/umc-dev.c
new file mode 100644
index 00000000000..aa44e1c1a10
--- /dev/null
+++ b/drivers/uwb/umc-dev.c
@@ -0,0 +1,104 @@
+/*
+ * UWB Multi-interface Controller device management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * This file is released under the GNU GPL v2.
+ */
+#include <linux/kernel.h>
+#include <linux/uwb/umc.h>
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+static void umc_device_release(struct device *dev)
+{
+ struct umc_dev *umc = to_umc_dev(dev);
+
+ kfree(umc);
+}
+
+/**
+ * umc_device_create - allocate a child UMC device
+ * @parent: parent of the new UMC device.
+ * @n: index of the new device.
+ *
+ * The new UMC device will have a bus ID of the parent with '-n'
+ * appended.
+ */
+struct umc_dev *umc_device_create(struct device *parent, int n)
+{
+ struct umc_dev *umc;
+
+ umc = kzalloc(sizeof(struct umc_dev), GFP_KERNEL);
+ if (umc) {
+ snprintf(umc->dev.bus_id, sizeof(umc->dev.bus_id), "%s-%d",
+ parent->bus_id, n);
+ umc->dev.parent = parent;
+ umc->dev.bus = &umc_bus_type;
+ umc->dev.release = umc_device_release;
+
+ umc->dev.dma_mask = parent->dma_mask;
+ }
+ return umc;
+}
+EXPORT_SYMBOL_GPL(umc_device_create);
+
+/**
+ * umc_device_register - register a UMC device
+ * @umc: pointer to the UMC device
+ *
+ * The memory resource for the UMC device is acquired and the device
+ * registered with the system.
+ */
+int umc_device_register(struct umc_dev *umc)
+{
+ int err;
+
+ d_fnstart(3, &umc->dev, "(umc_dev %p)\n", umc);
+
+ err = request_resource(umc->resource.parent, &umc->resource);
+ if (err < 0) {
+ dev_err(&umc->dev, "can't allocate resource range "
+ "%016Lx to %016Lx: %d\n",
+ (unsigned long long)umc->resource.start,
+ (unsigned long long)umc->resource.end,
+ err);
+ goto error_request_resource;
+ }
+
+ err = device_register(&umc->dev);
+ if (err < 0)
+ goto error_device_register;
+ d_fnend(3, &umc->dev, "(umc_dev %p) = 0\n", umc);
+ return 0;
+
+error_device_register:
+ release_resource(&umc->resource);
+error_request_resource:
+ d_fnend(3, &umc->dev, "(umc_dev %p) = %d\n", umc, err);
+ return err;
+}
+EXPORT_SYMBOL_GPL(umc_device_register);
+
+/**
+ * umc_device_unregister - unregister a UMC device
+ * @umc: pointer to the UMC device
+ *
+ * First we unregister the device, make sure the driver can do it's
+ * resource release thing and then we try to release any left over
+ * resources. We take a ref to the device, to make sure it doesn't
+ * dissapear under our feet.
+ */
+void umc_device_unregister(struct umc_dev *umc)
+{
+ struct device *dev;
+ if (!umc)
+ return;
+ dev = get_device(&umc->dev);
+ d_fnstart(3, dev, "(umc_dev %p)\n", umc);
+ device_unregister(&umc->dev);
+ release_resource(&umc->resource);
+ d_fnend(3, dev, "(umc_dev %p) = void\n", umc);
+ put_device(dev);
+}
+EXPORT_SYMBOL_GPL(umc_device_unregister);
diff --git a/drivers/uwb/umc-drv.c b/drivers/uwb/umc-drv.c
new file mode 100644
index 00000000000..367b5eb85d6
--- /dev/null
+++ b/drivers/uwb/umc-drv.c
@@ -0,0 +1,31 @@
+/*
+ * UWB Multi-interface Controller driver management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * This file is released under the GNU GPL v2.
+ */
+#include <linux/kernel.h>
+#include <linux/uwb/umc.h>
+
+int __umc_driver_register(struct umc_driver *umc_drv, struct module *module,
+ const char *mod_name)
+{
+ umc_drv->driver.name = umc_drv->name;
+ umc_drv->driver.owner = module;
+ umc_drv->driver.mod_name = mod_name;
+ umc_drv->driver.bus = &umc_bus_type;
+
+ return driver_register(&umc_drv->driver);
+}
+EXPORT_SYMBOL_GPL(__umc_driver_register);
+
+/**
+ * umc_driver_register - unregister a UMC capabiltity driver.
+ * @umc_drv: pointer to the driver.
+ */
+void umc_driver_unregister(struct umc_driver *umc_drv)
+{
+ driver_unregister(&umc_drv->driver);
+}
+EXPORT_SYMBOL_GPL(umc_driver_unregister);
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c
new file mode 100644
index 00000000000..6d232c35d07
--- /dev/null
+++ b/drivers/uwb/uwb-debug.c
@@ -0,0 +1,367 @@
+/*
+ * Ultra Wide Band
+ * Debug support
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * FIXME: doc
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+
+#include <linux/uwb/debug-cmd.h>
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+#include "uwb-internal.h"
+
+void dump_bytes(struct device *dev, const void *_buf, size_t rsize)
+{
+ const char *buf = _buf;
+ char line[32];
+ size_t offset = 0;
+ int cnt, cnt2;
+ for (cnt = 0; cnt < rsize; cnt += 8) {
+ size_t rtop = rsize - cnt < 8 ? rsize - cnt : 8;
+ for (offset = cnt2 = 0; cnt2 < rtop; cnt2++) {
+ offset += scnprintf(line + offset, sizeof(line) - offset,
+ "%02x ", buf[cnt + cnt2] & 0xff);
+ }
+ if (dev)
+ dev_info(dev, "%s\n", line);
+ else
+ printk(KERN_INFO "%s\n", line);
+ }
+}
+EXPORT_SYMBOL_GPL(dump_bytes);
+
+/*
+ * Debug interface
+ *
+ * Per radio controller debugfs files (in uwb/uwbN/):
+ *
+ * command: Flexible command interface (see <linux/uwb/debug-cmd.h>).
+ *
+ * reservations: information on reservations.
+ *
+ * accept: Set to true (Y or 1) to accept reservation requests from
+ * peers.
+ *
+ * drp_avail: DRP availability information.
+ */
+
+struct uwb_dbg {
+ struct uwb_pal pal;
+
+ u32 accept;
+ struct list_head rsvs;
+
+ struct dentry *root_d;
+ struct dentry *command_f;
+ struct dentry *reservations_f;
+ struct dentry *accept_f;
+ struct dentry *drp_avail_f;
+};
+
+static struct dentry *root_dir;
+
+static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+ struct device *dev = &rc->uwb_dev.dev;
+ struct uwb_dev_addr devaddr;
+ char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
+
+ uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
+ if (rsv->target.type == UWB_RSV_TARGET_DEV)
+ devaddr = rsv->target.dev->dev_addr;
+ else
+ devaddr = rsv->target.devaddr;
+ uwb_dev_addr_print(target, sizeof(target), &devaddr);
+
+ dev_dbg(dev, "debug: rsv %s -> %s: %s\n",
+ owner, target, uwb_rsv_state_str(rsv->state));
+}
+
+static int cmd_rsv_establish(struct uwb_rc *rc,
+ struct uwb_dbg_cmd_rsv_establish *cmd)
+{
+ struct uwb_mac_addr macaddr;
+ struct uwb_rsv *rsv;
+ struct uwb_dev *target;
+ int ret;
+
+ memcpy(&macaddr, cmd->target, sizeof(macaddr));
+ target = uwb_dev_get_by_macaddr(rc, &macaddr);
+ if (target == NULL)
+ return -ENODEV;
+
+ rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, NULL);
+ if (rsv == NULL) {
+ uwb_dev_put(target);
+ return -ENOMEM;
+ }
+
+ rsv->owner = &rc->uwb_dev;
+ rsv->target.type = UWB_RSV_TARGET_DEV;
+ rsv->target.dev = target;
+ rsv->type = cmd->type;
+ rsv->max_mas = cmd->max_mas;
+ rsv->min_mas = cmd->min_mas;
+ rsv->sparsity = cmd->sparsity;
+
+ ret = uwb_rsv_establish(rsv);
+ if (ret)
+ uwb_rsv_destroy(rsv);
+ else
+ list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
+
+ return ret;
+}
+
+static int cmd_rsv_terminate(struct uwb_rc *rc,
+ struct uwb_dbg_cmd_rsv_terminate *cmd)
+{
+ struct uwb_rsv *rsv, *found = NULL;
+ int i = 0;
+
+ list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) {
+ if (i == cmd->index) {
+ found = rsv;
+ break;
+ }
+ }
+ if (!found)
+ return -EINVAL;
+
+ list_del(&found->pal_node);
+ uwb_rsv_terminate(found);
+
+ return 0;
+}
+
+static int command_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+
+ return 0;
+}
+
+static ssize_t command_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *off)
+{
+ struct uwb_rc *rc = file->private_data;
+ struct uwb_dbg_cmd cmd;
+ int ret;
+
+ if (len != sizeof(struct uwb_dbg_cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd, buf, len) != 0)
+ return -EFAULT;
+
+ switch (cmd.type) {
+ case UWB_DBG_CMD_RSV_ESTABLISH:
+ ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
+ break;
+ case UWB_DBG_CMD_RSV_TERMINATE:
+ ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret < 0 ? ret : len;
+}
+
+static struct file_operations command_fops = {
+ .open = command_open,
+ .write = command_write,
+ .read = NULL,
+ .llseek = no_llseek,
+ .owner = THIS_MODULE,
+};
+
+static int reservations_print(struct seq_file *s, void *p)
+{
+ struct uwb_rc *rc = s->private;
+ struct uwb_rsv *rsv;
+
+ mutex_lock(&rc->rsvs_mutex);
+
+ list_for_each_entry(rsv, &rc->reservations, rc_node) {
+ struct uwb_dev_addr devaddr;
+ char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
+ bool is_owner;
+ char buf[72];
+
+ uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
+ if (rsv->target.type == UWB_RSV_TARGET_DEV) {
+ devaddr = rsv->target.dev->dev_addr;
+ is_owner = &rc->uwb_dev == rsv->owner;
+ } else {
+ devaddr = rsv->target.devaddr;
+ is_owner = true;
+ }
+ uwb_dev_addr_print(target, sizeof(target), &devaddr);
+
+ seq_printf(s, "%c %s -> %s: %s\n",
+ is_owner ? 'O' : 'T',
+ owner, target, uwb_rsv_state_str(rsv->state));
+ seq_printf(s, " stream: %d type: %s\n",
+ rsv->stream, uwb_rsv_type_str(rsv->type));
+ bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS);
+ seq_printf(s, " %s\n", buf);
+ }
+
+ mutex_unlock(&rc->rsvs_mutex);
+
+ return 0;
+}
+
+static int reservations_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, reservations_print, inode->i_private);
+}
+
+static struct file_operations reservations_fops = {
+ .open = reservations_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int drp_avail_print(struct seq_file *s, void *p)
+{
+ struct uwb_rc *rc = s->private;
+ char buf[72];
+
+ bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.global, UWB_NUM_MAS);
+ seq_printf(s, "global: %s\n", buf);
+ bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.local, UWB_NUM_MAS);
+ seq_printf(s, "local: %s\n", buf);
+ bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.pending, UWB_NUM_MAS);
+ seq_printf(s, "pending: %s\n", buf);
+
+ return 0;
+}
+
+static int drp_avail_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, drp_avail_print, inode->i_private);
+}
+
+static struct file_operations drp_avail_fops = {
+ .open = drp_avail_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static void uwb_dbg_new_rsv(struct uwb_rsv *rsv)
+{
+ struct uwb_rc *rc = rsv->rc;
+
+ if (rc->dbg->accept)
+ uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, NULL);
+}
+
+/**
+ * uwb_dbg_add_rc - add a debug interface for a radio controller
+ * @rc: the radio controller
+ */
+void uwb_dbg_add_rc(struct uwb_rc *rc)
+{
+ rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
+ if (rc->dbg == NULL)
+ return;
+
+ INIT_LIST_HEAD(&rc->dbg->rsvs);
+
+ uwb_pal_init(&rc->dbg->pal);
+ rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
+ uwb_pal_register(rc, &rc->dbg->pal);
+ if (root_dir) {
+ rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
+ root_dir);
+ rc->dbg->command_f = debugfs_create_file("command", 0200,
+ rc->dbg->root_d, rc,
+ &command_fops);
+ rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
+ rc->dbg->root_d, rc,
+ &reservations_fops);
+ rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
+ rc->dbg->root_d,
+ &rc->dbg->accept);
+ rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
+ rc->dbg->root_d, rc,
+ &drp_avail_fops);
+ }
+}
+
+/**
+ * uwb_dbg_add_rc - remove a radio controller's debug interface
+ * @rc: the radio controller
+ */
+void uwb_dbg_del_rc(struct uwb_rc *rc)
+{
+ struct uwb_rsv *rsv, *t;
+
+ if (rc->dbg == NULL)
+ return;
+
+ list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
+ uwb_rsv_destroy(rsv);
+ }
+
+ uwb_pal_unregister(rc, &rc->dbg->pal);
+
+ if (root_dir) {
+ debugfs_remove(rc->dbg->drp_avail_f);
+ debugfs_remove(rc->dbg->accept_f);
+ debugfs_remove(rc->dbg->reservations_f);
+ debugfs_remove(rc->dbg->command_f);
+ debugfs_remove(rc->dbg->root_d);
+ }
+}
+
+/**
+ * uwb_dbg_exit - initialize the debug interface sub-module
+ */
+void uwb_dbg_init(void)
+{
+ root_dir = debugfs_create_dir("uwb", NULL);
+}
+
+/**
+ * uwb_dbg_exit - clean-up the debug interface sub-module
+ */
+void uwb_dbg_exit(void)
+{
+ debugfs_remove(root_dir);
+}
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h
new file mode 100644
index 00000000000..2ad307d1296
--- /dev/null
+++ b/drivers/uwb/uwb-internal.h
@@ -0,0 +1,305 @@
+/*
+ * Ultra Wide Band
+ * UWB internal API
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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 contains most of the internal API for UWB. This is stuff used
+ * across the stack that of course, is of no interest to the rest.
+ *
+ * Some parts might end up going public (like uwb_rc_*())...
+ */
+
+#ifndef __UWB_INTERNAL_H__
+#define __UWB_INTERNAL_H__
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/uwb.h>
+#include <linux/mutex.h>
+
+struct uwb_beca_e;
+
+/* General device API */
+extern void uwb_dev_init(struct uwb_dev *uwb_dev);
+extern int __uwb_dev_offair(struct uwb_dev *, struct uwb_rc *);
+extern int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
+ struct uwb_rc *parent_rc);
+extern void uwb_dev_rm(struct uwb_dev *uwb_dev);
+extern void uwbd_dev_onair(struct uwb_rc *, struct uwb_beca_e *);
+extern void uwbd_dev_offair(struct uwb_beca_e *);
+void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event);
+
+/* General UWB Radio Controller Internal API */
+extern struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *);
+static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc)
+{
+ uwb_dev_get(&rc->uwb_dev);
+ return rc;
+}
+
+static inline void __uwb_rc_put(struct uwb_rc *rc)
+{
+ uwb_dev_put(&rc->uwb_dev);
+}
+
+extern int uwb_rc_reset(struct uwb_rc *rc);
+extern int uwb_rc_beacon(struct uwb_rc *rc,
+ int channel, unsigned bpst_offset);
+extern int uwb_rc_scan(struct uwb_rc *rc,
+ unsigned channel, enum uwb_scan_type type,
+ unsigned bpst_offset);
+extern int uwb_rc_send_all_drp_ie(struct uwb_rc *rc);
+extern ssize_t uwb_rc_print_IEs(struct uwb_rc *rc, char *, size_t);
+extern void uwb_rc_ie_init(struct uwb_rc *);
+extern void uwb_rc_ie_init(struct uwb_rc *);
+extern ssize_t uwb_rc_ie_setup(struct uwb_rc *);
+extern void uwb_rc_ie_release(struct uwb_rc *);
+extern int uwb_rc_ie_add(struct uwb_rc *,
+ const struct uwb_ie_hdr *, size_t);
+extern int uwb_rc_ie_rm(struct uwb_rc *, enum uwb_ie);
+
+extern const char *uwb_rc_strerror(unsigned code);
+
+/*
+ * Time to wait for a response to an RC command.
+ *
+ * Some commands can take a long time to response. e.g., START_BEACON
+ * may scan for several superframes before joining an existing beacon
+ * group and this can take around 600 ms.
+ */
+#define UWB_RC_CMD_TIMEOUT_MS 1000 /* ms */
+
+/*
+ * Notification/Event Handlers
+ */
+
+struct uwb_rc_neh;
+
+void uwb_rc_neh_create(struct uwb_rc *rc);
+void uwb_rc_neh_destroy(struct uwb_rc *rc);
+
+struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
+ u8 expected_type, u16 expected_event,
+ uwb_rc_cmd_cb_f cb, void *arg);
+void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
+void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
+void uwb_rc_neh_put(struct uwb_rc_neh *neh);
+
+/* Event size tables */
+extern int uwb_est_create(void);
+extern void uwb_est_destroy(void);
+
+
+/*
+ * UWB Events & management daemon
+ */
+
+/**
+ * enum uwb_event_type - types of UWB management daemon events
+ *
+ * The UWB management daemon (uwbd) can receive two types of events:
+ * UWB_EVT_TYPE_NOTIF - notification from the radio controller.
+ * UWB_EVT_TYPE_MSG - a simple message.
+ */
+enum uwb_event_type {
+ UWB_EVT_TYPE_NOTIF,
+ UWB_EVT_TYPE_MSG,
+};
+
+/**
+ * struct uwb_event_notif - an event for a radio controller notification
+ * @size: Size of the buffer (ie: Guaranteed to contain at least
+ * a full 'struct uwb_rceb')
+ * @rceb: Pointer to a kmalloced() event payload
+ */
+struct uwb_event_notif {
+ size_t size;
+ struct uwb_rceb *rceb;
+};
+
+/**
+ * enum uwb_event_message - an event for a message for asynchronous processing
+ *
+ * UWB_EVT_MSG_RESET - reset the radio controller and all PAL hardware.
+ */
+enum uwb_event_message {
+ UWB_EVT_MSG_RESET,
+};
+
+/**
+ * UWB Event
+ * @rc: Radio controller that emitted the event (referenced)
+ * @ts_jiffies: Timestamp, when was it received
+ * @type: This event's type.
+ */
+struct uwb_event {
+ struct list_head list_node;
+ struct uwb_rc *rc;
+ unsigned long ts_jiffies;
+ enum uwb_event_type type;
+ union {
+ struct uwb_event_notif notif;
+ enum uwb_event_message message;
+ };
+};
+
+extern void uwbd_start(void);
+extern void uwbd_stop(void);
+extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask);
+extern void uwbd_event_queue(struct uwb_event *);
+void uwbd_flush(struct uwb_rc *rc);
+
+/* UWB event handlers */
+extern int uwbd_evt_handle_rc_beacon(struct uwb_event *);
+extern int uwbd_evt_handle_rc_beacon_size(struct uwb_event *);
+extern int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *);
+extern int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *);
+extern int uwbd_evt_handle_rc_drp(struct uwb_event *);
+extern int uwbd_evt_handle_rc_drp_avail(struct uwb_event *);
+
+int uwbd_msg_handle_reset(struct uwb_event *evt);
+
+
+/*
+ * Address management
+ */
+int uwb_rc_dev_addr_assign(struct uwb_rc *rc);
+int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt);
+
+/*
+ * UWB Beacon Cache
+ *
+ * Each beacon we received is kept in a cache--when we receive that
+ * beacon consistently, that means there is a new device that we have
+ * to add to the system.
+ */
+
+extern unsigned long beacon_timeout_ms;
+
+/** Beacon cache list */
+struct uwb_beca {
+ struct list_head list;
+ size_t entries;
+ struct mutex mutex;
+};
+
+extern struct uwb_beca uwb_beca;
+
+/**
+ * Beacon cache entry
+ *
+ * @jiffies_refresh: last time a beacon was received that refreshed
+ * this cache entry.
+ * @uwb_dev: device connected to this beacon. This pointer is not
+ * safe, you need to get it with uwb_dev_try_get()
+ *
+ * @hits: how many time we have seen this beacon since last time we
+ * cleared it
+ */
+struct uwb_beca_e {
+ struct mutex mutex;
+ struct kref refcnt;
+ struct list_head node;
+ struct uwb_mac_addr *mac_addr;
+ struct uwb_dev_addr dev_addr;
+ u8 hits;
+ unsigned long ts_jiffies;
+ struct uwb_dev *uwb_dev;
+ struct uwb_rc_evt_beacon *be;
+ struct stats lqe_stats, rssi_stats; /* radio statistics */
+};
+struct uwb_beacon_frame;
+extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *,
+ char *, size_t);
+extern struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *,
+ struct uwb_beacon_frame *,
+ unsigned long);
+
+extern void uwb_bce_kfree(struct kref *_bce);
+static inline void uwb_bce_get(struct uwb_beca_e *bce)
+{
+ kref_get(&bce->refcnt);
+}
+static inline void uwb_bce_put(struct uwb_beca_e *bce)
+{
+ kref_put(&bce->refcnt, uwb_bce_kfree);
+}
+extern void uwb_beca_purge(void);
+extern void uwb_beca_release(void);
+
+struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
+ const struct uwb_dev_addr *devaddr);
+struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
+ const struct uwb_mac_addr *macaddr);
+
+/* -- UWB Sysfs representation */
+extern struct class uwb_rc_class;
+extern struct device_attribute dev_attr_mac_address;
+extern struct device_attribute dev_attr_beacon;
+extern struct device_attribute dev_attr_scan;
+
+/* -- DRP Bandwidth allocator: bandwidth allocations, reservations, DRP */
+void uwb_rsv_init(struct uwb_rc *rc);
+int uwb_rsv_setup(struct uwb_rc *rc);
+void uwb_rsv_cleanup(struct uwb_rc *rc);
+
+void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state);
+void uwb_rsv_remove(struct uwb_rsv *rsv);
+struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
+ struct uwb_ie_drp *drp_ie);
+void uwb_rsv_sched_update(struct uwb_rc *rc);
+
+void uwb_drp_handle_timeout(struct uwb_rsv *rsv);
+int uwb_drp_ie_update(struct uwb_rsv *rsv);
+void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie);
+
+void uwb_drp_avail_init(struct uwb_rc *rc);
+int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_ie_update(struct uwb_rc *rc);
+
+/* -- PAL support */
+void uwb_rc_pal_init(struct uwb_rc *rc);
+
+/* -- Misc */
+
+extern ssize_t uwb_mac_frame_hdr_print(char *, size_t,
+ const struct uwb_mac_frame_hdr *);
+
+/* -- Debug interface */
+void uwb_dbg_init(void);
+void uwb_dbg_exit(void);
+void uwb_dbg_add_rc(struct uwb_rc *rc);
+void uwb_dbg_del_rc(struct uwb_rc *rc);
+
+/* Workarounds for version specific stuff */
+
+static inline void uwb_dev_lock(struct uwb_dev *uwb_dev)
+{
+ down(&uwb_dev->dev.sem);
+}
+
+static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev)
+{
+ up(&uwb_dev->dev.sem);
+}
+
+#endif /* #ifndef __UWB_INTERNAL_H__ */
diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c
new file mode 100644
index 00000000000..78908416e42
--- /dev/null
+++ b/drivers/uwb/uwbd.c
@@ -0,0 +1,410 @@
+/*
+ * Ultra Wide Band
+ * Neighborhood Management Daemon
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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 daemon takes care of maintaing information that describes the
+ * UWB neighborhood that the radios in this machine can see. It also
+ * keeps a tab of which devices are visible, makes sure each HC sits
+ * on a different channel to avoid interfering, etc.
+ *
+ * Different drivers (radio controller, device, any API in general)
+ * communicate with this daemon through an event queue. Daemon wakes
+ * up, takes a list of events and handles them one by one; handling
+ * function is extracted from a table based on the event's type and
+ * subtype. Events are freed only if the handling function says so.
+ *
+ * . Lock protecting the event list has to be an spinlock and locked
+ * with IRQSAVE because it might be called from an interrupt
+ * context (ie: when events arrive and the notification drops
+ * down from the ISR).
+ *
+ * . UWB radio controller drivers queue events to the daemon using
+ * uwbd_event_queue(). They just get the event, chew it to make it
+ * look like UWBD likes it and pass it in a buffer allocated with
+ * uwb_event_alloc().
+ *
+ * EVENTS
+ *
+ * Events have a type, a subtype, a lenght, some other stuff and the
+ * data blob, which depends on the event. The header is 'struct
+ * uwb_event'; for payloads, see 'struct uwbd_evt_*'.
+ *
+ * EVENT HANDLER TABLES
+ *
+ * To find a handling function for an event, the type is used to index
+ * a subtype-table in the type-table. The subtype-table is indexed
+ * with the subtype to get the function that handles the event. Start
+ * with the main type-table 'uwbd_evt_type_handler'.
+ *
+ * DEVICES
+ *
+ * Devices are created when a bunch of beacons have been received and
+ * it is stablished that the device has stable radio presence. CREATED
+ * only, not configured. Devices are ONLY configured when an
+ * Application-Specific IE Probe is receieved, in which the device
+ * declares which Protocol ID it groks. Then the device is CONFIGURED
+ * (and the driver->probe() stuff of the device model is invoked).
+ *
+ * Devices are considered disconnected when a certain number of
+ * beacons are not received in an amount of time.
+ *
+ * Handler functions are called normally uwbd_evt_handle_*().
+ */
+
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/freezer.h>
+#include "uwb-internal.h"
+
+#define D_LOCAL 1
+#include <linux/uwb/debug.h>
+
+
+/**
+ * UWBD Event handler function signature
+ *
+ * Return !0 if the event needs not to be freed (ie the handler
+ * takes/took care of it). 0 means the daemon code will free the
+ * event.
+ *
+ * @evt->rc is already referenced and guaranteed to exist. See
+ * uwb_evt_handle().
+ */
+typedef int (*uwbd_evt_handler_f)(struct uwb_event *);
+
+/**
+ * Properties of a UWBD event
+ *
+ * @handler: the function that will handle this event
+ * @name: text name of event
+ */
+struct uwbd_event {
+ uwbd_evt_handler_f handler;
+ const char *name;
+};
+
+/** Table of handlers for and properties of the UWBD Radio Control Events */
+static
+struct uwbd_event uwbd_events[] = {
+ [UWB_RC_EVT_BEACON] = {
+ .handler = uwbd_evt_handle_rc_beacon,
+ .name = "BEACON_RECEIVED"
+ },
+ [UWB_RC_EVT_BEACON_SIZE] = {
+ .handler = uwbd_evt_handle_rc_beacon_size,
+ .name = "BEACON_SIZE_CHANGE"
+ },
+ [UWB_RC_EVT_BPOIE_CHANGE] = {
+ .handler = uwbd_evt_handle_rc_bpoie_change,
+ .name = "BPOIE_CHANGE"
+ },
+ [UWB_RC_EVT_BP_SLOT_CHANGE] = {
+ .handler = uwbd_evt_handle_rc_bp_slot_change,
+ .name = "BP_SLOT_CHANGE"
+ },
+ [UWB_RC_EVT_DRP_AVAIL] = {
+ .handler = uwbd_evt_handle_rc_drp_avail,
+ .name = "DRP_AVAILABILITY_CHANGE"
+ },
+ [UWB_RC_EVT_DRP] = {
+ .handler = uwbd_evt_handle_rc_drp,
+ .name = "DRP"
+ },
+ [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
+ .handler = uwbd_evt_handle_rc_dev_addr_conflict,
+ .name = "DEV_ADDR_CONFLICT",
+ },
+};
+
+
+
+struct uwbd_evt_type_handler {
+ const char *name;
+ struct uwbd_event *uwbd_events;
+ size_t size;
+};
+
+#define UWBD_EVT_TYPE_HANDLER(n,a) { \
+ .name = (n), \
+ .uwbd_events = (a), \
+ .size = sizeof(a)/sizeof((a)[0]) \
+}
+
+
+/** Table of handlers for each UWBD Event type. */
+static
+struct uwbd_evt_type_handler uwbd_evt_type_handlers[] = {
+ [UWB_RC_CET_GENERAL] = UWBD_EVT_TYPE_HANDLER("RC", uwbd_events)
+};
+
+static const
+size_t uwbd_evt_type_handlers_len =
+ sizeof(uwbd_evt_type_handlers) / sizeof(uwbd_evt_type_handlers[0]);
+
+static const struct uwbd_event uwbd_message_handlers[] = {
+ [UWB_EVT_MSG_RESET] = {
+ .handler = uwbd_msg_handle_reset,
+ .name = "reset",
+ },
+};
+
+static DEFINE_MUTEX(uwbd_event_mutex);
+
+/**
+ * Handle an URC event passed to the UWB Daemon
+ *
+ * @evt: the event to handle
+ * @returns: 0 if the event can be kfreed, !0 on the contrary
+ * (somebody else took ownership) [coincidentally, returning
+ * a <0 errno code will free it :)].
+ *
+ * Looks up the two indirection tables (one for the type, one for the
+ * subtype) to decide which function handles it and then calls the
+ * handler.
+ *
+ * The event structure passed to the event handler has the radio
+ * controller in @evt->rc referenced. The reference will be dropped
+ * once the handler returns, so if it needs it for longer (async),
+ * it'll need to take another one.
+ */
+static
+int uwbd_event_handle_urc(struct uwb_event *evt)
+{
+ struct uwbd_evt_type_handler *type_table;
+ uwbd_evt_handler_f handler;
+ u8 type, context;
+ u16 event;
+
+ type = evt->notif.rceb->bEventType;
+ event = le16_to_cpu(evt->notif.rceb->wEvent);
+ context = evt->notif.rceb->bEventContext;
+
+ if (type > uwbd_evt_type_handlers_len) {
+ printk(KERN_ERR "UWBD: event type %u: unknown (too high)\n", type);
+ return -EINVAL;
+ }
+ type_table = &uwbd_evt_type_handlers[type];
+ if (type_table->uwbd_events == NULL) {
+ printk(KERN_ERR "UWBD: event type %u: unknown\n", type);
+ return -EINVAL;
+ }
+ if (event > type_table->size) {
+ printk(KERN_ERR "UWBD: event %s[%u]: unknown (too high)\n",
+ type_table->name, event);
+ return -EINVAL;
+ }
+ handler = type_table->uwbd_events[event].handler;
+ if (handler == NULL) {
+ printk(KERN_ERR "UWBD: event %s[%u]: unknown\n", type_table->name, event);
+ return -EINVAL;
+ }
+ return (*handler)(evt);
+}
+
+static void uwbd_event_handle_message(struct uwb_event *evt)
+{
+ struct uwb_rc *rc;
+ int result;
+
+ rc = evt->rc;
+
+ if (evt->message < 0 || evt->message >= ARRAY_SIZE(uwbd_message_handlers)) {
+ dev_err(&rc->uwb_dev.dev, "UWBD: invalid message type %d\n", evt->message);
+ return;
+ }
+
+ /* If this is a reset event we need to drop the
+ * uwbd_event_mutex or it deadlocks when the reset handler
+ * attempts to flush the uwbd events. */
+ if (evt->message == UWB_EVT_MSG_RESET)
+ mutex_unlock(&uwbd_event_mutex);
+
+ result = uwbd_message_handlers[evt->message].handler(evt);
+ if (result < 0)
+ dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n",
+ uwbd_message_handlers[evt->message].name, result);
+
+ if (evt->message == UWB_EVT_MSG_RESET)
+ mutex_lock(&uwbd_event_mutex);
+}
+
+static void uwbd_event_handle(struct uwb_event *evt)
+{
+ struct uwb_rc *rc;
+ int should_keep;
+
+ rc = evt->rc;
+
+ if (rc->ready) {
+ switch (evt->type) {
+ case UWB_EVT_TYPE_NOTIF:
+ should_keep = uwbd_event_handle_urc(evt);
+ if (should_keep <= 0)
+ kfree(evt->notif.rceb);
+ break;
+ case UWB_EVT_TYPE_MSG:
+ uwbd_event_handle_message(evt);
+ break;
+ default:
+ dev_err(&rc->uwb_dev.dev, "UWBD: invalid event type %d\n", evt->type);
+ break;
+ }
+ }
+
+ __uwb_rc_put(rc); /* for the __uwb_rc_get() in uwb_rc_notif_cb() */
+}
+/* The UWB Daemon */
+
+
+/** Daemon's PID: used to decide if we can queue or not */
+static int uwbd_pid;
+/** Daemon's task struct for managing the kthread */
+static struct task_struct *uwbd_task;
+/** Daemon's waitqueue for waiting for new events */
+static DECLARE_WAIT_QUEUE_HEAD(uwbd_wq);
+/** Daemon's list of events; we queue/dequeue here */
+static struct list_head uwbd_event_list = LIST_HEAD_INIT(uwbd_event_list);
+/** Daemon's list lock to protect concurent access */
+static DEFINE_SPINLOCK(uwbd_event_list_lock);
+
+
+/**
+ * UWB Daemon
+ *
+ * Listens to all UWB notifications and takes care to track the state
+ * of the UWB neighboorhood for the kernel. When we do a run, we
+ * spinlock, move the list to a private copy and release the
+ * lock. Hold it as little as possible. Not a conflict: it is
+ * guaranteed we own the events in the private list.
+ *
+ * FIXME: should change so we don't have a 1HZ timer all the time, but
+ * only if there are devices.
+ */
+static int uwbd(void *unused)
+{
+ unsigned long flags;
+ struct list_head list = LIST_HEAD_INIT(list);
+ struct uwb_event *evt, *nxt;
+ int should_stop = 0;
+ while (1) {
+ wait_event_interruptible_timeout(
+ uwbd_wq,
+ !list_empty(&uwbd_event_list)
+ || (should_stop = kthread_should_stop()),
+ HZ);
+ if (should_stop)
+ break;
+ try_to_freeze();
+
+ mutex_lock(&uwbd_event_mutex);
+ spin_lock_irqsave(&uwbd_event_list_lock, flags);
+ list_splice_init(&uwbd_event_list, &list);
+ spin_unlock_irqrestore(&uwbd_event_list_lock, flags);
+ list_for_each_entry_safe(evt, nxt, &list, list_node) {
+ list_del(&evt->list_node);
+ uwbd_event_handle(evt);
+ kfree(evt);
+ }
+ mutex_unlock(&uwbd_event_mutex);
+
+ uwb_beca_purge(); /* Purge devices that left */
+ }
+ return 0;
+}
+
+
+/** Start the UWB daemon */
+void uwbd_start(void)
+{
+ uwbd_task = kthread_run(uwbd, NULL, "uwbd");
+ if (uwbd_task == NULL)
+ printk(KERN_ERR "UWB: Cannot start management daemon; "
+ "UWB won't work\n");
+ else
+ uwbd_pid = uwbd_task->pid;
+}
+
+/* Stop the UWB daemon and free any unprocessed events */
+void uwbd_stop(void)
+{
+ unsigned long flags;
+ struct uwb_event *evt, *nxt;
+ kthread_stop(uwbd_task);
+ spin_lock_irqsave(&uwbd_event_list_lock, flags);
+ uwbd_pid = 0;
+ list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) {
+ if (evt->type == UWB_EVT_TYPE_NOTIF)
+ kfree(evt->notif.rceb);
+ kfree(evt);
+ }
+ spin_unlock_irqrestore(&uwbd_event_list_lock, flags);
+ uwb_beca_release();
+}
+
+/*
+ * Queue an event for the management daemon
+ *
+ * When some lower layer receives an event, it uses this function to
+ * push it forward to the UWB daemon.
+ *
+ * Once you pass the event, you don't own it any more, but the daemon
+ * does. It will uwb_event_free() it when done, so make sure you
+ * uwb_event_alloc()ed it or bad things will happen.
+ *
+ * If the daemon is not running, we just free the event.
+ */
+void uwbd_event_queue(struct uwb_event *evt)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&uwbd_event_list_lock, flags);
+ if (uwbd_pid != 0) {
+ list_add(&evt->list_node, &uwbd_event_list);
+ wake_up_all(&uwbd_wq);
+ } else {
+ __uwb_rc_put(evt->rc);
+ if (evt->type == UWB_EVT_TYPE_NOTIF)
+ kfree(evt->notif.rceb);
+ kfree(evt);
+ }
+ spin_unlock_irqrestore(&uwbd_event_list_lock, flags);
+ return;
+}
+
+void uwbd_flush(struct uwb_rc *rc)
+{
+ struct uwb_event *evt, *nxt;
+
+ mutex_lock(&uwbd_event_mutex);
+
+ spin_lock_irq(&uwbd_event_list_lock);
+ list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) {
+ if (evt->rc == rc) {
+ __uwb_rc_put(rc);
+ list_del(&evt->list_node);
+ if (evt->type == UWB_EVT_TYPE_NOTIF)
+ kfree(evt->notif.rceb);
+ kfree(evt);
+ }
+ }
+ spin_unlock_irq(&uwbd_event_list_lock);
+
+ mutex_unlock(&uwbd_event_mutex);
+}
diff --git a/drivers/uwb/whc-rc.c b/drivers/uwb/whc-rc.c
new file mode 100644
index 00000000000..1711deadb11
--- /dev/null
+++ b/drivers/uwb/whc-rc.c
@@ -0,0 +1,520 @@
+/*
+ * Wireless Host Controller: Radio Control Interface (WHCI v0.95[2.3])
+ * Radio Control command/event transport to the UWB stack
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * Initialize and hook up the Radio Control interface.
+ *
+ * For each device probed, creates an 'struct whcrc' which contains
+ * just the representation of the UWB Radio Controller, and the logic
+ * for reading notifications and passing them to the UWB Core.
+ *
+ * So we initialize all of those, register the UWB Radio Controller
+ * and setup the notification/event handle to pipe the notifications
+ * to the UWB management Daemon.
+ *
+ * Once uwb_rc_add() is called, the UWB stack takes control, resets
+ * the radio and readies the device to take commands the UWB
+ * API/user-space.
+ *
+ * Note this driver is just a transport driver; the commands are
+ * formed at the UWB stack and given to this driver who will deliver
+ * them to the hw and transfer the replies/notifications back to the
+ * UWB stack through the UWB daemon (UWBD).
+ */
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/uwb.h>
+#include <linux/uwb/whci.h>
+#include <linux/uwb/umc.h>
+#include "uwb-internal.h"
+
+#define D_LOCAL 0
+#include <linux/uwb/debug.h>
+
+/**
+ * Descriptor for an instance of the UWB Radio Control Driver that
+ * attaches to the URC interface of the WHCI PCI card.
+ *
+ * Unless there is a lock specific to the 'data members', all access
+ * is protected by uwb_rc->mutex.
+ */
+struct whcrc {
+ struct umc_dev *umc_dev;
+ struct uwb_rc *uwb_rc; /* UWB host controller */
+
+ unsigned long area;
+ void __iomem *rc_base;
+ size_t rc_len;
+ spinlock_t irq_lock;
+
+ void *evt_buf, *cmd_buf;
+ dma_addr_t evt_dma_buf, cmd_dma_buf;
+ wait_queue_head_t cmd_wq;
+ struct work_struct event_work;
+};
+
+/**
+ * Execute an UWB RC command on WHCI/RC
+ *
+ * @rc: Instance of a Radio Controller that is a whcrc
+ * @cmd: Buffer containing the RCCB and payload to execute
+ * @cmd_size: Size of the command buffer.
+ *
+ * We copy the command into whcrc->cmd_buf (as it is pretty and
+ * aligned`and physically contiguous) and then press the right keys in
+ * the controller's URCCMD register to get it to read it. We might
+ * have to wait for the cmd_sem to be open to us.
+ *
+ * NOTE: rc's mutex has to be locked
+ */
+static int whcrc_cmd(struct uwb_rc *uwb_rc,
+ const struct uwb_rccb *cmd, size_t cmd_size)
+{
+ int result = 0;
+ struct whcrc *whcrc = uwb_rc->priv;
+ struct device *dev = &whcrc->umc_dev->dev;
+ u32 urccmd;
+
+ d_fnstart(3, dev, "(%p, %p, %zu)\n", uwb_rc, cmd, cmd_size);
+ might_sleep();
+
+ if (cmd_size >= 4096) {
+ result = -E2BIG;
+ goto error;
+ }
+
+ /*
+ * If the URC is halted, then the hardware has reset itself.
+ * Attempt to recover by restarting the device and then return
+ * an error as it's likely that the current command isn't
+ * valid for a newly started RC.
+ */
+ if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) {
+ dev_err(dev, "requesting reset of halted radio controller\n");
+ uwb_rc_reset_all(uwb_rc);
+ result = -EIO;
+ goto error;
+ }
+
+ result = wait_event_timeout(whcrc->cmd_wq,
+ !(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2);
+ if (result == 0) {
+ dev_err(dev, "device is not ready to execute commands\n");
+ result = -ETIMEDOUT;
+ goto error;
+ }
+
+ memmove(whcrc->cmd_buf, cmd, cmd_size);
+ le_writeq(whcrc->cmd_dma_buf, whcrc->rc_base + URCCMDADDR);
+
+ spin_lock(&whcrc->irq_lock);
+ urccmd = le_readl(whcrc->rc_base + URCCMD);
+ urccmd &= ~(URCCMD_EARV | URCCMD_SIZE_MASK);
+ le_writel(urccmd | URCCMD_ACTIVE | URCCMD_IWR | cmd_size,
+ whcrc->rc_base + URCCMD);
+ spin_unlock(&whcrc->irq_lock);
+
+error:
+ d_fnend(3, dev, "(%p, %p, %zu) = %d\n",
+ uwb_rc, cmd, cmd_size, result);
+ return result;
+}
+
+static int whcrc_reset(struct uwb_rc *rc)
+{
+ struct whcrc *whcrc = rc->priv;
+
+ return umc_controller_reset(whcrc->umc_dev);
+}
+
+/**
+ * Reset event reception mechanism and tell hw we are ready to get more
+ *
+ * We have read all the events in the event buffer, so we are ready to
+ * reset it to the beginning.
+ *
+ * This is only called during initialization or after an event buffer
+ * has been retired. This means we can be sure that event processing
+ * is disabled and it's safe to update the URCEVTADDR register.
+ *
+ * There's no need to wait for the event processing to start as the
+ * URC will not clear URCCMD_ACTIVE until (internal) event buffer
+ * space is available.
+ */
+static
+void whcrc_enable_events(struct whcrc *whcrc)
+{
+ struct device *dev = &whcrc->umc_dev->dev;
+ u32 urccmd;
+
+ d_fnstart(4, dev, "(whcrc %p)\n", whcrc);
+
+ le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR);
+
+ spin_lock(&whcrc->irq_lock);
+ urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE;
+ le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD);
+ spin_unlock(&whcrc->irq_lock);
+
+ d_fnend(4, dev, "(whcrc %p) = void\n", whcrc);
+}
+
+static void whcrc_event_work(struct work_struct *work)
+{
+ struct whcrc *whcrc = container_of(work, struct whcrc, event_work);
+ struct device *dev = &whcrc->umc_dev->dev;
+ size_t size;
+ u64 urcevtaddr;
+
+ urcevtaddr = le_readq(whcrc->rc_base + URCEVTADDR);
+ size = urcevtaddr & URCEVTADDR_OFFSET_MASK;
+
+ d_printf(3, dev, "received %zu octet event\n", size);
+ d_dump(4, dev, whcrc->evt_buf, size > 32 ? 32 : size);
+
+ uwb_rc_neh_grok(whcrc->uwb_rc, whcrc->evt_buf, size);
+ whcrc_enable_events(whcrc);
+}
+
+/**
+ * Catch interrupts?
+ *
+ * We ack inmediately (and expect the hw to do the right thing and
+ * raise another IRQ if things have changed :)
+ */
+static
+irqreturn_t whcrc_irq_cb(int irq, void *_whcrc)
+{
+ struct whcrc *whcrc = _whcrc;
+ struct device *dev = &whcrc->umc_dev->dev;
+ u32 urcsts;
+
+ urcsts = le_readl(whcrc->rc_base + URCSTS);
+ if (!(urcsts & URCSTS_INT_MASK))
+ return IRQ_NONE;
+ le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS);
+
+ d_printf(4, dev, "acked 0x%08x, urcsts 0x%08x\n",
+ le_readl(whcrc->rc_base + URCSTS), urcsts);
+
+ if (urcsts & URCSTS_HSE) {
+ dev_err(dev, "host system error -- hardware halted\n");
+ /* FIXME: do something sensible here */
+ goto out;
+ }
+ if (urcsts & URCSTS_ER) {
+ d_printf(3, dev, "ER: event ready\n");
+ schedule_work(&whcrc->event_work);
+ }
+ if (urcsts & URCSTS_RCI) {
+ d_printf(3, dev, "RCI: ready to execute another command\n");
+ wake_up_all(&whcrc->cmd_wq);
+ }
+out:
+ return IRQ_HANDLED;
+}
+
+
+/**
+ * Initialize a UMC RC interface: map regions, get (shared) IRQ
+ */
+static
+int whcrc_setup_rc_umc(struct whcrc *whcrc)
+{
+ int result = 0;
+ struct device *dev = &whcrc->umc_dev->dev;
+ struct umc_dev *umc_dev = whcrc->umc_dev;
+
+ whcrc->area = umc_dev->resource.start;
+ whcrc->rc_len = umc_dev->resource.end - umc_dev->resource.start + 1;
+ result = -EBUSY;
+ if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME)
+ == NULL) {
+ dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n",
+ whcrc->rc_len, whcrc->area, result);
+ goto error_request_region;
+ }
+
+ whcrc->rc_base = ioremap_nocache(whcrc->area, whcrc->rc_len);
+ if (whcrc->rc_base == NULL) {
+ dev_err(dev, "can't ioremap registers (%zu bytes @ 0x%lx): %d\n",
+ whcrc->rc_len, whcrc->area, result);
+ goto error_ioremap_nocache;
+ }
+
+ result = request_irq(umc_dev->irq, whcrc_irq_cb, IRQF_SHARED,
+ KBUILD_MODNAME, whcrc);
+ if (result < 0) {
+ dev_err(dev, "can't allocate IRQ %d: %d\n",
+ umc_dev->irq, result);
+ goto error_request_irq;
+ }
+
+ result = -ENOMEM;
+ whcrc->cmd_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
+ &whcrc->cmd_dma_buf, GFP_KERNEL);
+ if (whcrc->cmd_buf == NULL) {
+ dev_err(dev, "Can't allocate cmd transfer buffer\n");
+ goto error_cmd_buffer;
+ }
+
+ whcrc->evt_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
+ &whcrc->evt_dma_buf, GFP_KERNEL);
+ if (whcrc->evt_buf == NULL) {
+ dev_err(dev, "Can't allocate evt transfer buffer\n");
+ goto error_evt_buffer;
+ }
+ d_printf(3, dev, "UWB RC Interface: %zu bytes at 0x%p, irq %u\n",
+ whcrc->rc_len, whcrc->rc_base, umc_dev->irq);
+ return 0;
+
+error_evt_buffer:
+ dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
+ whcrc->cmd_dma_buf);
+error_cmd_buffer:
+ free_irq(umc_dev->irq, whcrc);
+error_request_irq:
+ iounmap(whcrc->rc_base);
+error_ioremap_nocache:
+ release_mem_region(whcrc->area, whcrc->rc_len);
+error_request_region:
+ return result;
+}
+
+
+/**
+ * Release RC's UMC resources
+ */
+static
+void whcrc_release_rc_umc(struct whcrc *whcrc)
+{
+ struct umc_dev *umc_dev = whcrc->umc_dev;
+
+ dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->evt_buf,
+ whcrc->evt_dma_buf);
+ dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
+ whcrc->cmd_dma_buf);
+ free_irq(umc_dev->irq, whcrc);
+ iounmap(whcrc->rc_base);
+ release_mem_region(whcrc->area, whcrc->rc_len);
+}
+
+
+/**
+ * whcrc_start_rc - start a WHCI radio controller
+ * @whcrc: the radio controller to start
+ *
+ * Reset the UMC device, start the radio controller, enable events and
+ * finally enable interrupts.
+ */
+static int whcrc_start_rc(struct uwb_rc *rc)
+{
+ struct whcrc *whcrc = rc->priv;
+ int result = 0;
+ struct device *dev = &whcrc->umc_dev->dev;
+ unsigned long start, duration;
+
+ /* Reset the thing */
+ le_writel(URCCMD_RESET, whcrc->rc_base + URCCMD);
+ if (d_test(3))
+ start = jiffies;
+ if (whci_wait_for(dev, whcrc->rc_base + URCCMD, URCCMD_RESET, 0,
+ 5000, "device to reset at init") < 0) {
+ result = -EBUSY;
+ goto error;
+ } else if (d_test(3)) {
+ duration = jiffies - start;
+ if (duration > msecs_to_jiffies(40))
+ dev_err(dev, "Device took %ums to "
+ "reset. MAX expected: 40ms\n",
+ jiffies_to_msecs(duration));
+ }
+
+ /* Set the event buffer, start the controller (enable IRQs later) */
+ le_writel(0, whcrc->rc_base + URCINTR);
+ le_writel(URCCMD_RS, whcrc->rc_base + URCCMD);
+ result = -ETIMEDOUT;
+ if (d_test(3))
+ start = jiffies;
+ if (whci_wait_for(dev, whcrc->rc_base + URCSTS, URCSTS_HALTED, 0,
+ 5000, "device to start") < 0)
+ goto error;
+ if (d_test(3)) {
+ duration = jiffies - start;
+ if (duration > msecs_to_jiffies(40))
+ dev_err(dev, "Device took %ums to start. "
+ "MAX expected: 40ms\n",
+ jiffies_to_msecs(duration));
+ }
+ whcrc_enable_events(whcrc);
+ result = 0;
+ le_writel(URCINTR_EN_ALL, whcrc->rc_base + URCINTR);
+error:
+ return result;
+}
+
+
+/**
+ * whcrc_stop_rc - stop a WHCI radio controller
+ * @whcrc: the radio controller to stop
+ *
+ * Disable interrupts and cancel any pending event processing work
+ * before clearing the Run/Stop bit.
+ */
+static
+void whcrc_stop_rc(struct uwb_rc *rc)
+{
+ struct whcrc *whcrc = rc->priv;
+ struct umc_dev *umc_dev = whcrc->umc_dev;
+
+ le_writel(0, whcrc->rc_base + URCINTR);
+ cancel_work_sync(&whcrc->event_work);
+
+ le_writel(0, whcrc->rc_base + URCCMD);
+ whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS,
+ URCSTS_HALTED, 0, 40, "URCSTS.HALTED");
+}
+
+static void whcrc_init(struct whcrc *whcrc)
+{
+ spin_lock_init(&whcrc->irq_lock);
+ init_waitqueue_head(&whcrc->cmd_wq);
+ INIT_WORK(&whcrc->event_work, whcrc_event_work);
+}
+
+/**
+ * Initialize the radio controller.
+ *
+ * NOTE: we setup whcrc->uwb_rc before calling uwb_rc_add(); in the
+ * IRQ handler we use that to determine if the hw is ready to
+ * handle events. Looks like a race condition, but it really is
+ * not.
+ */
+static
+int whcrc_probe(struct umc_dev *umc_dev)
+{
+ int result;
+ struct uwb_rc *uwb_rc;
+ struct whcrc *whcrc;
+ struct device *dev = &umc_dev->dev;
+
+ d_fnstart(3, dev, "(umc_dev %p)\n", umc_dev);
+ result = -ENOMEM;
+ uwb_rc = uwb_rc_alloc();
+ if (uwb_rc == NULL) {
+ dev_err(dev, "unable to allocate RC instance\n");
+ goto error_rc_alloc;
+ }
+ whcrc = kzalloc(sizeof(*whcrc), GFP_KERNEL);
+ if (whcrc == NULL) {
+ dev_err(dev, "unable to allocate WHC-RC instance\n");
+ goto error_alloc;
+ }
+ whcrc_init(whcrc);
+ whcrc->umc_dev = umc_dev;
+
+ result = whcrc_setup_rc_umc(whcrc);
+ if (result < 0) {
+ dev_err(dev, "Can't setup RC UMC interface: %d\n", result);
+ goto error_setup_rc_umc;
+ }
+ whcrc->uwb_rc = uwb_rc;
+
+ uwb_rc->owner = THIS_MODULE;
+ uwb_rc->cmd = whcrc_cmd;
+ uwb_rc->reset = whcrc_reset;
+ uwb_rc->start = whcrc_start_rc;
+ uwb_rc->stop = whcrc_stop_rc;
+
+ result = uwb_rc_add(uwb_rc, dev, whcrc);
+ if (result < 0)
+ goto error_rc_add;
+ umc_set_drvdata(umc_dev, whcrc);
+ d_fnend(3, dev, "(umc_dev %p) = 0\n", umc_dev);
+ return 0;
+
+error_rc_add:
+ whcrc_release_rc_umc(whcrc);
+error_setup_rc_umc:
+ kfree(whcrc);
+error_alloc:
+ uwb_rc_put(uwb_rc);
+error_rc_alloc:
+ d_fnend(3, dev, "(umc_dev %p) = %d\n", umc_dev, result);
+ return result;
+}
+
+/**
+ * Clean up the radio control resources
+ *
+ * When we up the command semaphore, everybody possibly held trying to
+ * execute a command should be granted entry and then they'll see the
+ * host is quiescing and up it (so it will chain to the next waiter).
+ * This should not happen (in any case), as we can only remove when
+ * there are no handles open...
+ */
+static void whcrc_remove(struct umc_dev *umc_dev)
+{
+ struct whcrc *whcrc = umc_get_drvdata(umc_dev);
+ struct uwb_rc *uwb_rc = whcrc->uwb_rc;
+
+ umc_set_drvdata(umc_dev, NULL);
+ uwb_rc_rm(uwb_rc);
+ whcrc_release_rc_umc(whcrc);
+ kfree(whcrc);
+ uwb_rc_put(uwb_rc);
+ d_printf(1, &umc_dev->dev, "freed whcrc %p\n", whcrc);
+}
+
+/* PCI device ID's that we handle [so it gets loaded] */
+static struct pci_device_id whcrc_id_table[] = {
+ { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
+ { /* empty last entry */ }
+};
+MODULE_DEVICE_TABLE(pci, whcrc_id_table);
+
+static struct umc_driver whcrc_driver = {
+ .name = "whc-rc",
+ .cap_id = UMC_CAP_ID_WHCI_RC,
+ .probe = whcrc_probe,
+ .remove = whcrc_remove,
+};
+
+static int __init whcrc_driver_init(void)
+{
+ return umc_driver_register(&whcrc_driver);
+}
+module_init(whcrc_driver_init);
+
+static void __exit whcrc_driver_exit(void)
+{
+ umc_driver_unregister(&whcrc_driver);
+}
+module_exit(whcrc_driver_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless Host Controller Radio Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/whci.c b/drivers/uwb/whci.c
new file mode 100644
index 00000000000..3df2388f908
--- /dev/null
+++ b/drivers/uwb/whci.c
@@ -0,0 +1,269 @@
+/*
+ * WHCI UWB Multi-interface Controller enumerator.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * This file is released under the GNU GPL v2.
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/uwb/whci.h>
+#include <linux/uwb/umc.h>
+
+struct whci_card {
+ struct pci_dev *pci;
+ void __iomem *uwbbase;
+ u8 n_caps;
+ struct umc_dev *devs[0];
+};
+
+
+/* Fix faulty HW :( */
+static
+u64 whci_capdata_quirks(struct whci_card *card, u64 capdata)
+{
+ u64 capdata_orig = capdata;
+ struct pci_dev *pci_dev = card->pci;
+ if (pci_dev->vendor == PCI_VENDOR_ID_INTEL
+ && (pci_dev->device == 0x0c3b || pci_dev->device == 0004)
+ && pci_dev->class == 0x0d1010) {
+ switch (UWBCAPDATA_TO_CAP_ID(capdata)) {
+ /* WLP capability has 0x100 bytes of aperture */
+ case 0x80:
+ capdata |= 0x40 << 8; break;
+ /* WUSB capability has 0x80 bytes of aperture
+ * and ID is 1 */
+ case 0x02:
+ capdata &= ~0xffff;
+ capdata |= 0x2001;
+ break;
+ }
+ }
+ if (capdata_orig != capdata)
+ dev_warn(&pci_dev->dev,
+ "PCI v%04x d%04x c%06x#%02x: "
+ "corrected capdata from %016Lx to %016Lx\n",
+ pci_dev->vendor, pci_dev->device, pci_dev->class,
+ (unsigned)UWBCAPDATA_TO_CAP_ID(capdata),
+ (unsigned long long)capdata_orig,
+ (unsigned long long)capdata);
+ return capdata;
+}
+
+
+/**
+ * whci_wait_for - wait for a WHCI register to be set
+ *
+ * Polls (for at most @max_ms ms) until '*@reg & @mask == @result'.
+ */
+int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result,
+ unsigned long max_ms, const char *tag)
+{
+ unsigned t = 0;
+ u32 val;
+ for (;;) {
+ val = le_readl(reg);
+ if ((val & mask) == result)
+ break;
+ msleep(10);
+ if (t >= max_ms) {
+ dev_err(dev, "timed out waiting for %s ", tag);
+ return -ETIMEDOUT;
+ }
+ t += 10;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(whci_wait_for);
+
+
+/*
+ * NOTE: the capinfo and capdata registers are slightly different
+ * (size and cap-id fields). So for cap #0, we need to fill
+ * in. Size comes from the size of the register block
+ * (statically calculated); cap_id comes from nowhere, we use
+ * zero, that is reserved, for the radio controller, because
+ * none was defined at the spec level.
+ */
+static int whci_add_cap(struct whci_card *card, int n)
+{
+ struct umc_dev *umc;
+ u64 capdata;
+ int bar, err;
+
+ umc = umc_device_create(&card->pci->dev, n);
+ if (umc == NULL)
+ return -ENOMEM;
+
+ capdata = le_readq(card->uwbbase + UWBCAPDATA(n));
+
+ bar = UWBCAPDATA_TO_BAR(capdata) << 1;
+
+ capdata = whci_capdata_quirks(card, capdata);
+ /* Capability 0 is the radio controller. It's size is 32
+ * bytes (WHCI0.95[2.3, T2-9]). */
+ umc->version = UWBCAPDATA_TO_VERSION(capdata);
+ umc->cap_id = n == 0 ? 0 : UWBCAPDATA_TO_CAP_ID(capdata);
+ umc->bar = bar;
+ umc->resource.start = pci_resource_start(card->pci, bar)
+ + UWBCAPDATA_TO_OFFSET(capdata);
+ umc->resource.end = umc->resource.start
+ + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1;
+ umc->resource.name = umc->dev.bus_id;
+ umc->resource.flags = card->pci->resource[bar].flags;
+ umc->resource.parent = &card->pci->resource[bar];
+ umc->irq = card->pci->irq;
+
+ err = umc_device_register(umc);
+ if (err < 0)
+ goto error;
+ card->devs[n] = umc;
+ return 0;
+
+error:
+ kfree(umc);
+ return err;
+}
+
+static void whci_del_cap(struct whci_card *card, int n)
+{
+ struct umc_dev *umc = card->devs[n];
+
+ if (umc != NULL)
+ umc_device_unregister(umc);
+}
+
+static int whci_n_caps(struct pci_dev *pci)
+{
+ void __iomem *uwbbase;
+ u64 capinfo;
+
+ uwbbase = pci_iomap(pci, 0, 8);
+ if (!uwbbase)
+ return -ENOMEM;
+ capinfo = le_readq(uwbbase + UWBCAPINFO);
+ pci_iounmap(pci, uwbbase);
+
+ return UWBCAPINFO_TO_N_CAPS(capinfo);
+}
+
+static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+ struct whci_card *card;
+ int err, n_caps, n;
+
+ err = pci_enable_device(pci);
+ if (err < 0)
+ goto error;
+ pci_enable_msi(pci);
+ pci_set_master(pci);
+ err = -ENXIO;
+ if (!pci_set_dma_mask(pci, DMA_64BIT_MASK))
+ pci_set_consistent_dma_mask(pci, DMA_64BIT_MASK);
+ else if (!pci_set_dma_mask(pci, DMA_32BIT_MASK))
+ pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK);
+ else
+ goto error_dma;
+
+ err = n_caps = whci_n_caps(pci);
+ if (n_caps < 0)
+ goto error_ncaps;
+
+ err = -ENOMEM;
+ card = kzalloc(sizeof(struct whci_card)
+ + sizeof(struct whci_dev *) * (n_caps + 1),
+ GFP_KERNEL);
+ if (card == NULL)
+ goto error_kzalloc;
+ card->pci = pci;
+ card->n_caps = n_caps;
+
+ err = -EBUSY;
+ if (!request_mem_region(pci_resource_start(pci, 0),
+ UWBCAPDATA_SIZE(card->n_caps),
+ "whci (capability data)"))
+ goto error_request_memregion;
+ err = -ENOMEM;
+ card->uwbbase = pci_iomap(pci, 0, UWBCAPDATA_SIZE(card->n_caps));
+ if (!card->uwbbase)
+ goto error_iomap;
+
+ /* Add each capability. */
+ for (n = 0; n <= card->n_caps; n++) {
+ err = whci_add_cap(card, n);
+ if (err < 0 && n == 0) {
+ dev_err(&pci->dev, "cannot bind UWB radio controller:"
+ " %d\n", err);
+ goto error_bind;
+ }
+ if (err < 0)
+ dev_warn(&pci->dev, "warning: cannot bind capability "
+ "#%u: %d\n", n, err);
+ }
+ pci_set_drvdata(pci, card);
+ return 0;
+
+error_bind:
+ pci_iounmap(pci, card->uwbbase);
+error_iomap:
+ release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
+error_request_memregion:
+ kfree(card);
+error_kzalloc:
+error_ncaps:
+error_dma:
+ pci_disable_msi(pci);
+ pci_disable_device(pci);
+error:
+ return err;
+}
+
+static void whci_remove(struct pci_dev *pci)
+{
+ struct whci_card *card = pci_get_drvdata(pci);
+ int n;
+
+ pci_set_drvdata(pci, NULL);
+ /* Unregister each capability in reverse (so the master device
+ * is unregistered last). */
+ for (n = card->n_caps; n >= 0 ; n--)
+ whci_del_cap(card, n);
+ pci_iounmap(pci, card->uwbbase);
+ release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
+ kfree(card);
+ pci_disable_msi(pci);
+ pci_disable_device(pci);
+}
+
+static struct pci_device_id whci_id_table[] = {
+ { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(pci, whci_id_table);
+
+
+static struct pci_driver whci_driver = {
+ .name = "whci",
+ .id_table = whci_id_table,
+ .probe = whci_probe,
+ .remove = whci_remove,
+};
+
+static int __init whci_init(void)
+{
+ return pci_register_driver(&whci_driver);
+}
+
+static void __exit whci_exit(void)
+{
+ pci_unregister_driver(&whci_driver);
+}
+
+module_init(whci_init);
+module_exit(whci_exit);
+
+MODULE_DESCRIPTION("WHCI UWB Multi-interface Controller enumerator");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/wlp/Makefile b/drivers/uwb/wlp/Makefile
new file mode 100644
index 00000000000..c72c11db5b1
--- /dev/null
+++ b/drivers/uwb/wlp/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_UWB_WLP) := wlp.o
+
+wlp-objs := \
+ driver.o \
+ eda.o \
+ messages.o \
+ sysfs.o \
+ txrx.o \
+ wlp-lc.o \
+ wss-lc.o
diff --git a/drivers/uwb/wlp/driver.c b/drivers/uwb/wlp/driver.c
new file mode 100644
index 00000000000..cb8d699b6a6
--- /dev/null
+++ b/drivers/uwb/wlp/driver.c
@@ -0,0 +1,43 @@
+/*
+ * WiMedia Logical Link Control Protocol (WLP)
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Reinette Chatre <reinette.chatre@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.
+ *
+ *
+ * Life cycle of WLP substack
+ *
+ * FIXME: Docs
+ */
+
+#include <linux/module.h>
+
+static int __init wlp_subsys_init(void)
+{
+ return 0;
+}
+module_init(wlp_subsys_init);
+
+static void __exit wlp_subsys_exit(void)
+{
+ return;
+}
+module_exit(wlp_subsys_exit);
+
+MODULE_AUTHOR("Reinette Chatre <reinette.chatre@intel.com>");
+MODULE_DESCRIPTION("WiMedia Logical Link Control Protocol (WLP)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/wlp/eda.c b/drivers/uwb/wlp/eda.c
new file mode 100644
index 00000000000..cdfe8dfc434
--- /dev/null
+++ b/drivers/uwb/wlp/eda.c
@@ -0,0 +1,449 @@
+/*
+ * WUSB Wire Adapter: WLP interface
+ * Ethernet to device address cache
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * 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.
+ *
+ *
+ * We need to be able to map ethernet addresses to device addresses
+ * and back because there is not explicit relationship between the eth
+ * addresses used in the ETH frames and the device addresses (no, it
+ * would not have been simpler to force as ETH address the MBOA MAC
+ * address...no, not at all :).
+ *
+ * A device has one MBOA MAC address and one device address. It is possible
+ * for a device to have more than one virtual MAC address (although a
+ * virtual address can be the same as the MBOA MAC address). The device
+ * address is guaranteed to be unique among the devices in the extended
+ * beacon group (see ECMA 17.1.1). We thus use the device address as index
+ * to this cache. We do allow searching based on virtual address as this
+ * is how Ethernet frames will be addressed.
+ *
+ * We need to support virtual EUI-48. Although, right now the virtual
+ * EUI-48 will always be the same as the MAC SAP address. The EDA cache
+ * entry thus contains a MAC SAP address as well as the virtual address
+ * (used to map the network stack address to a neighbor). When we move
+ * to support more than one virtual MAC on a host then this organization
+ * will have to change. Perhaps a neighbor has a list of WSSs, each with a
+ * tag and virtual EUI-48.
+ *
+ * On data transmission
+ * it is used to determine if the neighbor is connected and what WSS it
+ * belongs to. With this we know what tag to add to the WLP frame. Storing
+ * the WSS in the EDA cache may be overkill because we only support one
+ * WSS. Hopefully we will support more than one WSS at some point.
+ * On data reception it is used to determine the WSS based on
+ * the tag and address of the transmitting neighbor.
+ */
+
+#define D_LOCAL 5
+#include <linux/netdevice.h>
+#include <linux/uwb/debug.h>
+#include <linux/etherdevice.h>
+#include <linux/wlp.h>
+#include "wlp-internal.h"
+
+
+/* FIXME: cache is not purged, only on device close */
+
+/* FIXME: does not scale, change to dynamic array */
+
+/*
+ * Initialize the EDA cache
+ *
+ * @returns 0 if ok, < 0 errno code on error
+ *
+ * Call when the interface is being brought up
+ *
+ * NOTE: Keep it as a separate function as the implementation will
+ * change and be more complex.
+ */
+void wlp_eda_init(struct wlp_eda *eda)
+{
+ INIT_LIST_HEAD(&eda->cache);
+ spin_lock_init(&eda->lock);
+}
+
+/*
+ * Release the EDA cache
+ *
+ * @returns 0 if ok, < 0 errno code on error
+ *
+ * Called when the interface is brought down
+ */
+void wlp_eda_release(struct wlp_eda *eda)
+{
+ unsigned long flags;
+ struct wlp_eda_node *itr, *next;
+
+ spin_lock_irqsave(&eda->lock, flags);
+ list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
+ list_del(&itr->list_node);
+ kfree(itr);
+ }
+ spin_unlock_irqrestore(&eda->lock, flags);
+}
+
+/*
+ * Add an address mapping
+ *
+ * @returns 0 if ok, < 0 errno code on error
+ *
+ * An address mapping is initially created when the neighbor device is seen
+ * for the first time (it is "onair"). At this time the neighbor is not
+ * connected or associated with a WSS so we only populate the Ethernet and
+ * Device address fields.
+ *
+ */
+int wlp_eda_create_node(struct wlp_eda *eda,
+ const unsigned char eth_addr[ETH_ALEN],
+ const struct uwb_dev_addr *dev_addr)
+{
+ int result = 0;
+ struct wlp_eda_node *itr;
+ unsigned long flags;
+
+ BUG_ON(dev_addr == NULL || eth_addr == NULL);
+ spin_lock_irqsave(&eda->lock, flags);
+ list_for_each_entry(itr, &eda->cache, list_node) {
+ if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
+ printk(KERN_ERR "EDA cache already contains entry "
+ "for neighbor %02x:%02x\n",
+ dev_addr->data[1], dev_addr->data[0]);
+ result = -EEXIST;
+ goto out_unlock;
+ }
+ }
+ itr = kzalloc(sizeof(*itr), GFP_ATOMIC);
+ if (itr != NULL) {
+ memcpy(itr->eth_addr, eth_addr, sizeof(itr->eth_addr));
+ itr->dev_addr = *dev_addr;
+ list_add(&itr->list_node, &eda->cache);
+ } else
+ result = -ENOMEM;
+out_unlock:
+ spin_unlock_irqrestore(&eda->lock, flags);
+ return result;
+}
+
+/*
+ * Remove entry from EDA cache
+ *
+ * This is done when the device goes off air.
+ */
+void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr)
+{
+ struct wlp_eda_node *itr, *next;
+ unsigned long flags;
+
+ spin_lock_irqsave(&eda->lock, flags);
+ list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
+ if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
+ list_del(&itr->list_node);
+ kfree(itr);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&eda->lock, flags);
+}
+
+/*
+ * Update an address mapping
+ *
+ * @returns 0 if ok, < 0 errno code on error
+ */
+int wlp_eda_update_node(struct wlp_eda *eda,
+ const struct uwb_dev_addr *dev_addr,
+ struct wlp_wss *wss,
+ const unsigned char virt_addr[ETH_ALEN],
+ const u8 tag, const enum wlp_wss_connect state)
+{
+ int result = -ENOENT;
+ struct wlp_eda_node *itr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&eda->lock, flags);
+ list_for_each_entry(itr, &eda->cache, list_node) {
+ if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
+ /* Found it, update it */
+ itr->wss = wss;
+ memcpy(itr->virt_addr, virt_addr,
+ sizeof(itr->virt_addr));
+ itr->tag = tag;
+ itr->state = state;
+ result = 0;
+ goto out_unlock;
+ }
+ }
+ /* Not found */
+out_unlock:
+ spin_unlock_irqrestore(&eda->lock, flags);
+ return result;
+}
+
+/*
+ * Update only state field of an address mapping
+ *
+ * @returns 0 if ok, < 0 errno code on error
+ */
+int wlp_eda_update_node_state(struct wlp_eda *eda,
+ const struct uwb_dev_addr *dev_addr,
+ const enum wlp_wss_connect state)
+{
+ int result = -ENOENT;
+ struct wlp_eda_node *itr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&eda->lock, flags);
+ list_for_each_entry(itr, &eda->cache, list_node) {
+ if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
+ /* Found it, update it */
+ itr->state = state;
+ result = 0;
+ goto out_unlock;
+ }
+ }
+ /* Not found */
+out_unlock:
+ spin_unlock_irqrestore(&eda->lock, flags);
+ return result;
+}
+
+/*
+ * Return contents of EDA cache entry
+ *
+ * @dev_addr: index to EDA cache
+ * @eda_entry: pointer to where contents of EDA cache will be copied
+ */
+int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr,
+ struct wlp_eda_node *eda_entry)
+{
+ int result = -ENOENT;
+ struct wlp_eda_node *itr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&eda->lock, flags);
+ list_for_each_entry(itr, &eda->cache, list_node) {
+ if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
+ *eda_entry = *itr;
+ result = 0;
+ goto out_unlock;
+ }
+ }
+ /* Not found */
+out_unlock:
+ spin_unlock_irqrestore(&eda->lock, flags);
+ return result;
+}
+
+/*
+ * Execute function for every element in the cache
+ *
+ * @function: function to execute on element of cache (must be atomic)
+ * @priv: private data of function
+ * @returns: result of first function that failed, or last function
+ * executed if no function failed.
+ *
+ * Stop executing when function returns error for any element in cache.
+ *
+ * IMPORTANT: We are using a spinlock here: the function executed on each
+ * element has to be atomic.
+ */
+int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function,
+ void *priv)
+{
+ int result = 0;
+ struct wlp *wlp = container_of(eda, struct wlp, eda);
+ struct wlp_eda_node *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&eda->lock, flags);
+ list_for_each_entry(entry, &eda->cache, list_node) {
+ result = (*function)(wlp, entry, priv);
+ if (result < 0)
+ break;
+ }
+ spin_unlock_irqrestore(&eda->lock, flags);
+ return result;
+}
+
+/*
+ * Execute function for single element in the cache (return dev addr)
+ *
+ * @virt_addr: index into EDA cache used to determine which element to
+ * execute the function on
+ * @dev_addr: device address of element in cache will be returned using
+ * @dev_addr
+ * @function: function to execute on element of cache (must be atomic)
+ * @priv: private data of function
+ * @returns: result of function
+ *
+ * IMPORTANT: We are using a spinlock here: the function executed on the
+ * element has to be atomic.
+ */
+int wlp_eda_for_virtual(struct wlp_eda *eda,
+ const unsigned char virt_addr[ETH_ALEN],
+ struct uwb_dev_addr *dev_addr,
+ wlp_eda_for_each_f function,
+ void *priv)
+{
+ int result = 0;
+ struct wlp *wlp = container_of(eda, struct wlp, eda);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_eda_node *itr;
+ unsigned long flags;
+ int found = 0;
+
+ spin_lock_irqsave(&eda->lock, flags);
+ list_for_each_entry(itr, &eda->cache, list_node) {
+ if (!memcmp(itr->virt_addr, virt_addr,
+ sizeof(itr->virt_addr))) {
+ d_printf(6, dev, "EDA: looking for "
+ "%02x:%02x:%02x:%02x:%02x:%02x hit %02x:%02x "
+ "wss %p tag 0x%02x state %u\n",
+ virt_addr[0], virt_addr[1],
+ virt_addr[2], virt_addr[3],
+ virt_addr[4], virt_addr[5],
+ itr->dev_addr.data[1],
+ itr->dev_addr.data[0], itr->wss,
+ itr->tag, itr->state);
+ result = (*function)(wlp, itr, priv);
+ *dev_addr = itr->dev_addr;
+ found = 1;
+ break;
+ } else
+ d_printf(6, dev, "EDA: looking for "
+ "%02x:%02x:%02x:%02x:%02x:%02x "
+ "against "
+ "%02x:%02x:%02x:%02x:%02x:%02x miss\n",
+ virt_addr[0], virt_addr[1],
+ virt_addr[2], virt_addr[3],
+ virt_addr[4], virt_addr[5],
+ itr->virt_addr[0], itr->virt_addr[1],
+ itr->virt_addr[2], itr->virt_addr[3],
+ itr->virt_addr[4], itr->virt_addr[5]);
+ }
+ if (!found) {
+ if (printk_ratelimit())
+ dev_err(dev, "EDA: Eth addr %02x:%02x:%02x"
+ ":%02x:%02x:%02x not found.\n",
+ virt_addr[0], virt_addr[1],
+ virt_addr[2], virt_addr[3],
+ virt_addr[4], virt_addr[5]);
+ result = -ENODEV;
+ }
+ spin_unlock_irqrestore(&eda->lock, flags);
+ return result;
+}
+
+static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED",
+ "WLP_WSS_CONNECTED",
+ "WLP_WSS_CONNECT_FAILED",
+};
+
+static const char *wlp_wss_connect_state_str(unsigned id)
+{
+ if (id >= ARRAY_SIZE(__wlp_wss_connect_state))
+ return "unknown WSS connection state";
+ return __wlp_wss_connect_state[id];
+}
+
+/*
+ * View EDA cache from user space
+ *
+ * A debugging feature to give user visibility into the EDA cache. Also
+ * used to display members of WSS to user (called from wlp_wss_members_show())
+ */
+ssize_t wlp_eda_show(struct wlp *wlp, char *buf)
+{
+ ssize_t result = 0;
+ struct wlp_eda_node *entry;
+ unsigned long flags;
+ struct wlp_eda *eda = &wlp->eda;
+ spin_lock_irqsave(&eda->lock, flags);
+ result = scnprintf(buf, PAGE_SIZE, "#eth_addr dev_addr wss_ptr "
+ "tag state virt_addr\n");
+ list_for_each_entry(entry, &eda->cache, list_node) {
+ result += scnprintf(buf + result, PAGE_SIZE - result,
+ "%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x "
+ "%p 0x%02x %s "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ entry->eth_addr[0], entry->eth_addr[1],
+ entry->eth_addr[2], entry->eth_addr[3],
+ entry->eth_addr[4], entry->eth_addr[5],
+ entry->dev_addr.data[1],
+ entry->dev_addr.data[0], entry->wss,
+ entry->tag,
+ wlp_wss_connect_state_str(entry->state),
+ entry->virt_addr[0], entry->virt_addr[1],
+ entry->virt_addr[2], entry->virt_addr[3],
+ entry->virt_addr[4], entry->virt_addr[5]);
+ if (result >= PAGE_SIZE)
+ break;
+ }
+ spin_unlock_irqrestore(&eda->lock, flags);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_eda_show);
+
+/*
+ * Add new EDA cache entry based on user input in sysfs
+ *
+ * Should only be used for debugging.
+ *
+ * The WSS is assumed to be the only WSS supported. This needs to be
+ * redesigned when we support more than one WSS.
+ */
+ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size)
+{
+ ssize_t result;
+ struct wlp_eda *eda = &wlp->eda;
+ u8 eth_addr[6];
+ struct uwb_dev_addr dev_addr;
+ u8 tag;
+ unsigned state;
+
+ result = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx "
+ "%02hhx:%02hhx %02hhx %u\n",
+ &eth_addr[0], &eth_addr[1],
+ &eth_addr[2], &eth_addr[3],
+ &eth_addr[4], &eth_addr[5],
+ &dev_addr.data[1], &dev_addr.data[0], &tag, &state);
+ switch (result) {
+ case 6: /* no dev addr specified -- remove entry NOT IMPLEMENTED */
+ /*result = wlp_eda_rm(eda, eth_addr, &dev_addr);*/
+ result = -ENOSYS;
+ break;
+ case 10:
+ state = state >= 1 ? 1 : 0;
+ result = wlp_eda_create_node(eda, eth_addr, &dev_addr);
+ if (result < 0 && result != -EEXIST)
+ goto error;
+ /* Set virtual addr to be same as MAC */
+ result = wlp_eda_update_node(eda, &dev_addr, &wlp->wss,
+ eth_addr, tag, state);
+ if (result < 0)
+ goto error;
+ break;
+ default: /* bad format */
+ result = -EINVAL;
+ }
+error:
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(wlp_eda_store);
diff --git a/drivers/uwb/wlp/messages.c b/drivers/uwb/wlp/messages.c
new file mode 100644
index 00000000000..a64cb824171
--- /dev/null
+++ b/drivers/uwb/wlp/messages.c
@@ -0,0 +1,1946 @@
+/*
+ * WiMedia Logical Link Control Protocol (WLP)
+ * Message construction and parsing
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Reinette Chatre <reinette.chatre@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.
+ *
+ *
+ * FIXME: docs
+ */
+
+#include <linux/wlp.h>
+#define D_LOCAL 6
+#include <linux/uwb/debug.h>
+#include "wlp-internal.h"
+
+static
+const char *__wlp_assoc_frame[] = {
+ [WLP_ASSOC_D1] = "WLP_ASSOC_D1",
+ [WLP_ASSOC_D2] = "WLP_ASSOC_D2",
+ [WLP_ASSOC_M1] = "WLP_ASSOC_M1",
+ [WLP_ASSOC_M2] = "WLP_ASSOC_M2",
+ [WLP_ASSOC_M3] = "WLP_ASSOC_M3",
+ [WLP_ASSOC_M4] = "WLP_ASSOC_M4",
+ [WLP_ASSOC_M5] = "WLP_ASSOC_M5",
+ [WLP_ASSOC_M6] = "WLP_ASSOC_M6",
+ [WLP_ASSOC_M7] = "WLP_ASSOC_M7",
+ [WLP_ASSOC_M8] = "WLP_ASSOC_M8",
+ [WLP_ASSOC_F0] = "WLP_ASSOC_F0",
+ [WLP_ASSOC_E1] = "WLP_ASSOC_E1",
+ [WLP_ASSOC_E2] = "WLP_ASSOC_E2",
+ [WLP_ASSOC_C1] = "WLP_ASSOC_C1",
+ [WLP_ASSOC_C2] = "WLP_ASSOC_C2",
+ [WLP_ASSOC_C3] = "WLP_ASSOC_C3",
+ [WLP_ASSOC_C4] = "WLP_ASSOC_C4",
+};
+
+static const char *wlp_assoc_frame_str(unsigned id)
+{
+ if (id >= ARRAY_SIZE(__wlp_assoc_frame))
+ return "unknown association frame";
+ return __wlp_assoc_frame[id];
+}
+
+static const char *__wlp_assc_error[] = {
+ "none",
+ "Authenticator Failure",
+ "Rogue activity suspected",
+ "Device busy",
+ "Setup Locked",
+ "Registrar not ready",
+ "Invalid WSS selection",
+ "Message timeout",
+ "Enrollment session timeout",
+ "Device password invalid",
+ "Unsupported version",
+ "Internal error",
+ "Undefined error",
+ "Numeric comparison failure",
+ "Waiting for user input",
+};
+
+static const char *wlp_assc_error_str(unsigned id)
+{
+ if (id >= ARRAY_SIZE(__wlp_assc_error))
+ return "unknown WLP association error";
+ return __wlp_assc_error[id];
+}
+
+static inline void wlp_set_attr_hdr(struct wlp_attr_hdr *hdr, unsigned type,
+ size_t len)
+{
+ hdr->type = cpu_to_le16(type);
+ hdr->length = cpu_to_le16(len);
+}
+
+/*
+ * Populate fields of a constant sized attribute
+ *
+ * @returns: total size of attribute including size of new value
+ *
+ * We have two instances of this function (wlp_pset and wlp_set): one takes
+ * the value as a parameter, the other takes a pointer to the value as
+ * parameter. They thus only differ in how the value is assigned to the
+ * attribute.
+ *
+ * We use sizeof(*attr) - sizeof(struct wlp_attr_hdr) instead of
+ * sizeof(type) to be able to use this same code for the structures that
+ * contain 8bit enum values and be able to deal with pointer types.
+ */
+#define wlp_set(type, type_code, name) \
+static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
+{ \
+ d_fnstart(6, NULL, "(attribute %p)\n", attr); \
+ wlp_set_attr_hdr(&attr->hdr, type_code, \
+ sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \
+ attr->name = value; \
+ d_dump(6, NULL, attr, sizeof(*attr)); \
+ d_fnend(6, NULL, "(attribute %p)\n", attr); \
+ return sizeof(*attr); \
+}
+
+#define wlp_pset(type, type_code, name) \
+static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
+{ \
+ d_fnstart(6, NULL, "(attribute %p)\n", attr); \
+ wlp_set_attr_hdr(&attr->hdr, type_code, \
+ sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \
+ attr->name = *value; \
+ d_dump(6, NULL, attr, sizeof(*attr)); \
+ d_fnend(6, NULL, "(attribute %p)\n", attr); \
+ return sizeof(*attr); \
+}
+
+/**
+ * Populate fields of a variable attribute
+ *
+ * @returns: total size of attribute including size of new value
+ *
+ * Provided with a pointer to the memory area reserved for the
+ * attribute structure, the field is populated with the value. The
+ * reserved memory has to contain enough space for the value.
+ */
+#define wlp_vset(type, type_code, name) \
+static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value, \
+ size_t len) \
+{ \
+ d_fnstart(6, NULL, "(attribute %p)\n", attr); \
+ wlp_set_attr_hdr(&attr->hdr, type_code, len); \
+ memcpy(attr->name, value, len); \
+ d_dump(6, NULL, attr, sizeof(*attr) + len); \
+ d_fnend(6, NULL, "(attribute %p)\n", attr); \
+ return sizeof(*attr) + len; \
+}
+
+wlp_vset(char *, WLP_ATTR_DEV_NAME, dev_name)
+wlp_vset(char *, WLP_ATTR_MANUF, manufacturer)
+wlp_set(enum wlp_assoc_type, WLP_ATTR_MSG_TYPE, msg_type)
+wlp_vset(char *, WLP_ATTR_MODEL_NAME, model_name)
+wlp_vset(char *, WLP_ATTR_MODEL_NR, model_nr)
+wlp_vset(char *, WLP_ATTR_SERIAL, serial)
+wlp_vset(char *, WLP_ATTR_WSS_NAME, wss_name)
+wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_E, uuid_e)
+wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_R, uuid_r)
+wlp_pset(struct wlp_uuid *, WLP_ATTR_WSSID, wssid)
+wlp_pset(struct wlp_dev_type *, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
+/*wlp_pset(struct wlp_dev_type *, WLP_ATTR_SEC_DEV_TYPE, sec_dev_type)*/
+wlp_set(u8, WLP_ATTR_WLP_VER, version)
+wlp_set(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
+wlp_set(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
+wlp_set(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
+wlp_set(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
+wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_BCAST, wss_bcast)
+wlp_pset(struct wlp_nonce *, WLP_ATTR_ENRL_NONCE, enonce)
+wlp_pset(struct wlp_nonce *, WLP_ATTR_REG_NONCE, rnonce)
+wlp_set(u8, WLP_ATTR_WSS_TAG, wss_tag)
+wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_VIRT, wss_virt)
+
+/**
+ * Fill in the WSS information attributes
+ *
+ * We currently only support one WSS, and this is assumed in this function
+ * that can populate only one WSS information attribute.
+ */
+static size_t wlp_set_wss_info(struct wlp_attr_wss_info *attr,
+ struct wlp_wss *wss)
+{
+ size_t datalen;
+ void *ptr = attr->wss_info;
+ size_t used = sizeof(*attr);
+ d_fnstart(6, NULL, "(attribute %p)\n", attr);
+ datalen = sizeof(struct wlp_wss_info) + strlen(wss->name);
+ wlp_set_attr_hdr(&attr->hdr, WLP_ATTR_WSS_INFO, datalen);
+ used = wlp_set_wssid(ptr, &wss->wssid);
+ used += wlp_set_wss_name(ptr + used, wss->name, strlen(wss->name));
+ used += wlp_set_accept_enrl(ptr + used, wss->accept_enroll);
+ used += wlp_set_wss_sec_status(ptr + used, wss->secure_status);
+ used += wlp_set_wss_bcast(ptr + used, &wss->bcast);
+ d_dump(6, NULL, attr, sizeof(*attr) + datalen);
+ d_fnend(6, NULL, "(attribute %p, used %d)\n",
+ attr, (int)(sizeof(*attr) + used));
+ return sizeof(*attr) + used;
+}
+
+/**
+ * Verify attribute header
+ *
+ * @hdr: Pointer to attribute header that will be verified.
+ * @type: Expected attribute type.
+ * @len: Expected length of attribute value (excluding header).
+ *
+ * Most attribute values have a known length even when they do have a
+ * length field. This knowledge can be used via this function to verify
+ * that the length field matches the expected value.
+ */
+static int wlp_check_attr_hdr(struct wlp *wlp, struct wlp_attr_hdr *hdr,
+ enum wlp_attr_type type, unsigned len)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+
+ if (le16_to_cpu(hdr->type) != type) {
+ dev_err(dev, "WLP: unexpected header type. Expected "
+ "%u, got %u.\n", type, le16_to_cpu(hdr->type));
+ return -EINVAL;
+ }
+ if (le16_to_cpu(hdr->length) != len) {
+ dev_err(dev, "WLP: unexpected length in header. Expected "
+ "%u, got %u.\n", len, le16_to_cpu(hdr->length));
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * Check if header of WSS information attribute valid
+ *
+ * @returns: length of WSS attributes (value of length attribute field) if
+ * valid WSS information attribute found
+ * -ENODATA if no WSS information attribute found
+ * -EIO other error occured
+ *
+ * The WSS information attribute is optional. The function will be provided
+ * with a pointer to data that could _potentially_ be a WSS information
+ * attribute. If a valid WSS information attribute is found it will return
+ * 0, if no WSS information attribute is found it will return -ENODATA, and
+ * another error will be returned if it is a WSS information attribute, but
+ * some parsing failure occured.
+ */
+static int wlp_check_wss_info_attr_hdr(struct wlp *wlp,
+ struct wlp_attr_hdr *hdr, size_t buflen)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ size_t len;
+ int result = 0;
+
+ if (buflen < sizeof(*hdr)) {
+ dev_err(dev, "WLP: Not enough space in buffer to parse"
+ " WSS information attribute header.\n");
+ result = -EIO;
+ goto out;
+ }
+ if (le16_to_cpu(hdr->type) != WLP_ATTR_WSS_INFO) {
+ /* WSS information is optional */
+ result = -ENODATA;
+ goto out;
+ }
+ len = le16_to_cpu(hdr->length);
+ if (buflen < sizeof(*hdr) + len) {
+ dev_err(dev, "WLP: Not enough space in buffer to parse "
+ "variable data. Got %d, expected %d.\n",
+ (int)buflen, (int)(sizeof(*hdr) + len));
+ result = -EIO;
+ goto out;
+ }
+ result = len;
+out:
+ return result;
+}
+
+
+/**
+ * Get value of attribute from fixed size attribute field.
+ *
+ * @attr: Pointer to attribute field.
+ * @value: Pointer to variable in which attribute value will be placed.
+ * @buflen: Size of buffer in which attribute field (including header)
+ * can be found.
+ * @returns: Amount of given buffer consumed by parsing for this attribute.
+ *
+ * The size and type of the value is known by the type of the attribute.
+ */
+#define wlp_get(type, type_code, name) \
+ssize_t wlp_get_##name(struct wlp *wlp, struct wlp_attr_##name *attr, \
+ type *value, ssize_t buflen) \
+{ \
+ struct device *dev = &wlp->rc->uwb_dev.dev; \
+ if (buflen < 0) \
+ return -EINVAL; \
+ if (buflen < sizeof(*attr)) { \
+ dev_err(dev, "WLP: Not enough space in buffer to parse" \
+ " attribute field. Need %d, received %zu\n", \
+ (int)sizeof(*attr), buflen); \
+ return -EIO; \
+ } \
+ if (wlp_check_attr_hdr(wlp, &attr->hdr, type_code, \
+ sizeof(attr->name)) < 0) { \
+ dev_err(dev, "WLP: Header verification failed. \n"); \
+ return -EINVAL; \
+ } \
+ *value = attr->name; \
+ return sizeof(*attr); \
+}
+
+#define wlp_get_sparse(type, type_code, name) \
+ static wlp_get(type, type_code, name)
+
+/**
+ * Get value of attribute from variable sized attribute field.
+ *
+ * @max: The maximum size of this attribute. This value is dictated by
+ * the maximum value from the WLP specification.
+ *
+ * @attr: Pointer to attribute field.
+ * @value: Pointer to variable that will contain the value. The memory
+ * must already have been allocated for this value.
+ * @buflen: Size of buffer in which attribute field (including header)
+ * can be found.
+ * @returns: Amount of given bufferconsumed by parsing for this attribute.
+ */
+#define wlp_vget(type_val, type_code, name, max) \
+static ssize_t wlp_get_##name(struct wlp *wlp, \
+ struct wlp_attr_##name *attr, \
+ type_val *value, ssize_t buflen) \
+{ \
+ struct device *dev = &wlp->rc->uwb_dev.dev; \
+ size_t len; \
+ if (buflen < 0) \
+ return -EINVAL; \
+ if (buflen < sizeof(*attr)) { \
+ dev_err(dev, "WLP: Not enough space in buffer to parse" \
+ " header.\n"); \
+ return -EIO; \
+ } \
+ if (le16_to_cpu(attr->hdr.type) != type_code) { \
+ dev_err(dev, "WLP: Unexpected attribute type. Got %u, " \
+ "expected %u.\n", le16_to_cpu(attr->hdr.type), \
+ type_code); \
+ return -EINVAL; \
+ } \
+ len = le16_to_cpu(attr->hdr.length); \
+ if (len > max) { \
+ dev_err(dev, "WLP: Attribute larger than maximum " \
+ "allowed. Received %zu, max is %d.\n", len, \
+ (int)max); \
+ return -EFBIG; \
+ } \
+ if (buflen < sizeof(*attr) + len) { \
+ dev_err(dev, "WLP: Not enough space in buffer to parse "\
+ "variable data.\n"); \
+ return -EIO; \
+ } \
+ memcpy(value, (void *) attr + sizeof(*attr), len); \
+ return sizeof(*attr) + len; \
+}
+
+wlp_get(u8, WLP_ATTR_WLP_VER, version)
+wlp_get_sparse(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
+wlp_get_sparse(struct wlp_dev_type, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
+wlp_get_sparse(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
+wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_E, uuid_e)
+wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_R, uuid_r)
+wlp_get(struct wlp_uuid, WLP_ATTR_WSSID, wssid)
+wlp_get_sparse(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
+wlp_get_sparse(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
+wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_BCAST, wss_bcast)
+wlp_get_sparse(u8, WLP_ATTR_WSS_TAG, wss_tag)
+wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_VIRT, wss_virt)
+wlp_get_sparse(struct wlp_nonce, WLP_ATTR_ENRL_NONCE, enonce)
+wlp_get_sparse(struct wlp_nonce, WLP_ATTR_REG_NONCE, rnonce)
+
+/* The buffers for the device info attributes can be found in the
+ * wlp_device_info struct. These buffers contain one byte more than the
+ * max allowed by the spec - this is done to be able to add the
+ * terminating \0 for user display. This terminating byte is not required
+ * in the actual attribute field (because it has a length field) so the
+ * maximum allowed for this value is one less than its size in the
+ * structure.
+ */
+wlp_vget(char, WLP_ATTR_WSS_NAME, wss_name,
+ FIELD_SIZEOF(struct wlp_wss, name) - 1)
+wlp_vget(char, WLP_ATTR_DEV_NAME, dev_name,
+ FIELD_SIZEOF(struct wlp_device_info, name) - 1)
+wlp_vget(char, WLP_ATTR_MANUF, manufacturer,
+ FIELD_SIZEOF(struct wlp_device_info, manufacturer) - 1)
+wlp_vget(char, WLP_ATTR_MODEL_NAME, model_name,
+ FIELD_SIZEOF(struct wlp_device_info, model_name) - 1)
+wlp_vget(char, WLP_ATTR_MODEL_NR, model_nr,
+ FIELD_SIZEOF(struct wlp_device_info, model_nr) - 1)
+wlp_vget(char, WLP_ATTR_SERIAL, serial,
+ FIELD_SIZEOF(struct wlp_device_info, serial) - 1)
+
+/**
+ * Retrieve WSS Name, Accept enroll, Secure status, Broadcast from WSS info
+ *
+ * @attr: pointer to WSS name attribute in WSS information attribute field
+ * @info: structure that will be populated with data from WSS information
+ * field (WSS name, Accept enroll, secure status, broadcast address)
+ * @buflen: size of buffer
+ *
+ * Although the WSSID attribute forms part of the WSS info attribute it is
+ * retrieved separately and stored in a different location.
+ */
+static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp,
+ struct wlp_attr_hdr *attr,
+ struct wlp_wss_tmp_info *info,
+ ssize_t buflen)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ void *ptr = attr;
+ size_t used = 0;
+ ssize_t result = -EINVAL;
+
+ d_printf(6, dev, "WLP: WSS info: Retrieving WSS name\n");
+ result = wlp_get_wss_name(wlp, ptr, info->name, buflen);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSS name from "
+ "WSS info in D2 message.\n");
+ goto error_parse;
+ }
+ used += result;
+ d_printf(6, dev, "WLP: WSS info: Retrieving accept enroll\n");
+ result = wlp_get_accept_enrl(wlp, ptr + used, &info->accept_enroll,
+ buflen - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain accepting "
+ "enrollment from WSS info in D2 message.\n");
+ goto error_parse;
+ }
+ if (info->accept_enroll != 0 && info->accept_enroll != 1) {
+ dev_err(dev, "WLP: invalid value for accepting "
+ "enrollment in D2 message.\n");
+ result = -EINVAL;
+ goto error_parse;
+ }
+ used += result;
+ d_printf(6, dev, "WLP: WSS info: Retrieving secure status\n");
+ result = wlp_get_wss_sec_status(wlp, ptr + used, &info->sec_status,
+ buflen - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain secure "
+ "status from WSS info in D2 message.\n");
+ goto error_parse;
+ }
+ if (info->sec_status != 0 && info->sec_status != 1) {
+ dev_err(dev, "WLP: invalid value for secure "
+ "status in D2 message.\n");
+ result = -EINVAL;
+ goto error_parse;
+ }
+ used += result;
+ d_printf(6, dev, "WLP: WSS info: Retrieving broadcast\n");
+ result = wlp_get_wss_bcast(wlp, ptr + used, &info->bcast,
+ buflen - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain broadcast "
+ "address from WSS info in D2 message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = used;
+error_parse:
+ return result;
+}
+
+/**
+ * Create a new WSSID entry for the neighbor, allocate temporary storage
+ *
+ * Each neighbor can have many WSS active. We maintain a list of WSSIDs
+ * advertised by neighbor. During discovery we also cache information about
+ * these WSS in temporary storage.
+ *
+ * The temporary storage will be removed after it has been used (eg.
+ * displayed to user), the wssid element will be removed from the list when
+ * the neighbor is rediscovered or when it disappears.
+ */
+static struct wlp_wssid_e *wlp_create_wssid_e(struct wlp *wlp,
+ struct wlp_neighbor_e *neighbor)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_wssid_e *wssid_e;
+
+ wssid_e = kzalloc(sizeof(*wssid_e), GFP_KERNEL);
+ if (wssid_e == NULL) {
+ dev_err(dev, "WLP: unable to allocate memory "
+ "for WSS information.\n");
+ goto error_alloc;
+ }
+ wssid_e->info = kzalloc(sizeof(struct wlp_wss_tmp_info), GFP_KERNEL);
+ if (wssid_e->info == NULL) {
+ dev_err(dev, "WLP: unable to allocate memory "
+ "for temporary WSS information.\n");
+ kfree(wssid_e);
+ wssid_e = NULL;
+ goto error_alloc;
+ }
+ list_add(&wssid_e->node, &neighbor->wssid);
+error_alloc:
+ return wssid_e;
+}
+
+/**
+ * Parse WSS information attribute
+ *
+ * @attr: pointer to WSS information attribute header
+ * @buflen: size of buffer in which WSS information attribute appears
+ * @wssid: will place wssid from WSS info attribute in this location
+ * @wss_info: will place other information from WSS information attribute
+ * in this location
+ *
+ * memory for @wssid and @wss_info must be allocated when calling this
+ */
+static ssize_t wlp_get_wss_info(struct wlp *wlp, struct wlp_attr_wss_info *attr,
+ size_t buflen, struct wlp_uuid *wssid,
+ struct wlp_wss_tmp_info *wss_info)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ ssize_t result;
+ size_t len;
+ size_t used = 0;
+ void *ptr;
+
+ result = wlp_check_wss_info_attr_hdr(wlp, (struct wlp_attr_hdr *)attr,
+ buflen);
+ if (result < 0)
+ goto out;
+ len = result;
+ used = sizeof(*attr);
+ ptr = attr;
+ d_printf(6, dev, "WLP: WSS info: Retrieving WSSID\n");
+ result = wlp_get_wssid(wlp, ptr + used, wssid, buflen - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSSID from WSS info.\n");
+ goto out;
+ }
+ used += result;
+ result = wlp_get_wss_info_attrs(wlp, ptr + used, wss_info,
+ buflen - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSS information "
+ "from WSS information attributes. \n");
+ goto out;
+ }
+ used += result;
+ if (len + sizeof(*attr) != used) {
+ dev_err(dev, "WLP: Amount of data parsed does not "
+ "match length field. Parsed %zu, length "
+ "field %zu. \n", used, len);
+ result = -EINVAL;
+ goto out;
+ }
+ result = used;
+ d_printf(6, dev, "WLP: Successfully parsed WLP information "
+ "attribute. used %zu bytes\n", used);
+out:
+ return result;
+}
+
+/**
+ * Retrieve WSS info from association frame
+ *
+ * @attr: pointer to WSS information attribute
+ * @neighbor: ptr to neighbor being discovered, NULL if enrollment in
+ * progress
+ * @wss: ptr to WSS being enrolled in, NULL if discovery in progress
+ * @buflen: size of buffer in which WSS information appears
+ *
+ * The WSS information attribute appears in the D2 association message.
+ * This message is used in two ways: to discover all neighbors or to enroll
+ * into a WSS activated by a neighbor. During discovery we only want to
+ * store the WSS info in a cache, to be deleted right after it has been
+ * used (eg. displayed to the user). During enrollment we store the WSS
+ * information for the lifetime of enrollment.
+ *
+ * During discovery we are interested in all WSS information, during
+ * enrollment we are only interested in the WSS being enrolled in. Even so,
+ * when in enrollment we keep parsing the message after finding the WSS of
+ * interest, this simplifies the calling routine in that it can be sure
+ * that all WSS information attributes have been parsed out of the message.
+ *
+ * Association frame is process with nbmutex held. The list access is safe.
+ */
+static ssize_t wlp_get_all_wss_info(struct wlp *wlp,
+ struct wlp_attr_wss_info *attr,
+ struct wlp_neighbor_e *neighbor,
+ struct wlp_wss *wss, ssize_t buflen)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ size_t used = 0;
+ ssize_t result = -EINVAL;
+ struct wlp_attr_wss_info *cur;
+ struct wlp_uuid wssid;
+ struct wlp_wss_tmp_info wss_info;
+ unsigned enroll; /* 0 - discovery to cache, 1 - enrollment */
+ struct wlp_wssid_e *wssid_e;
+ char buf[WLP_WSS_UUID_STRSIZE];
+
+ d_fnstart(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d \n",
+ wlp, attr, neighbor, wss, (int)buflen);
+ if (buflen < 0)
+ goto out;
+
+ if (neighbor != NULL && wss == NULL)
+ enroll = 0; /* discovery */
+ else if (wss != NULL && neighbor == NULL)
+ enroll = 1; /* enrollment */
+ else
+ goto out;
+
+ cur = attr;
+ while (buflen - used > 0) {
+ memset(&wss_info, 0, sizeof(wss_info));
+ cur = (void *)cur + used;
+ result = wlp_get_wss_info(wlp, cur, buflen - used, &wssid,
+ &wss_info);
+ if (result == -ENODATA) {
+ result = used;
+ goto out;
+ } else if (result < 0) {
+ dev_err(dev, "WLP: Unable to parse WSS information "
+ "from WSS information attribute. \n");
+ result = -EINVAL;
+ goto error_parse;
+ }
+ if (enroll && !memcmp(&wssid, &wss->wssid, sizeof(wssid))) {
+ if (wss_info.accept_enroll != 1) {
+ dev_err(dev, "WLP: Requested WSS does "
+ "not accept enrollment.\n");
+ result = -EINVAL;
+ goto out;
+ }
+ memcpy(wss->name, wss_info.name, sizeof(wss->name));
+ wss->bcast = wss_info.bcast;
+ wss->secure_status = wss_info.sec_status;
+ wss->accept_enroll = wss_info.accept_enroll;
+ wss->state = WLP_WSS_STATE_PART_ENROLLED;
+ wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
+ d_printf(2, dev, "WLP: Found WSS %s. Enrolling.\n",
+ buf);
+ } else {
+ wssid_e = wlp_create_wssid_e(wlp, neighbor);
+ if (wssid_e == NULL) {
+ dev_err(dev, "WLP: Cannot create new WSSID "
+ "entry for neighbor %02x:%02x.\n",
+ neighbor->uwb_dev->dev_addr.data[1],
+ neighbor->uwb_dev->dev_addr.data[0]);
+ result = -ENOMEM;
+ goto out;
+ }
+ wssid_e->wssid = wssid;
+ *wssid_e->info = wss_info;
+ }
+ used += result;
+ }
+ result = used;
+error_parse:
+ if (result < 0 && !enroll) /* this was a discovery */
+ wlp_remove_neighbor_tmp_info(neighbor);
+out:
+ d_fnend(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d, "
+ "result %d \n", wlp, attr, neighbor, wss, (int)buflen,
+ (int)result);
+ return result;
+
+}
+
+/**
+ * Parse WSS information attributes into cache for discovery
+ *
+ * @attr: the first WSS information attribute in message
+ * @neighbor: the neighbor whose cache will be populated
+ * @buflen: size of the input buffer
+ */
+static ssize_t wlp_get_wss_info_to_cache(struct wlp *wlp,
+ struct wlp_attr_wss_info *attr,
+ struct wlp_neighbor_e *neighbor,
+ ssize_t buflen)
+{
+ return wlp_get_all_wss_info(wlp, attr, neighbor, NULL, buflen);
+}
+
+/**
+ * Parse WSS information attributes into WSS struct for enrollment
+ *
+ * @attr: the first WSS information attribute in message
+ * @wss: the WSS that will be enrolled
+ * @buflen: size of the input buffer
+ */
+static ssize_t wlp_get_wss_info_to_enroll(struct wlp *wlp,
+ struct wlp_attr_wss_info *attr,
+ struct wlp_wss *wss, ssize_t buflen)
+{
+ return wlp_get_all_wss_info(wlp, attr, NULL, wss, buflen);
+}
+
+/**
+ * Construct a D1 association frame
+ *
+ * We use the radio control functions to determine the values of the device
+ * properties. These are of variable length and the total space needed is
+ * tallied first before we start constructing the message. The radio
+ * control functions return strings that are terminated with \0. This
+ * character should not be included in the message (there is a length field
+ * accompanying it in the attribute).
+ */
+static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss,
+ struct sk_buff **skb)
+{
+
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = 0;
+ struct wlp_device_info *info;
+ size_t used = 0;
+ struct wlp_frame_assoc *_d1;
+ struct sk_buff *_skb;
+ void *d1_itr;
+
+ d_fnstart(6, dev, "wlp %p\n", wlp);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_setup_device_info(wlp);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to setup device "
+ "information for D1 message.\n");
+ goto error;
+ }
+ }
+ info = wlp->dev_info;
+ d_printf(6, dev, "Local properties:\n"
+ "Device name (%d bytes): %s\n"
+ "Model name (%d bytes): %s\n"
+ "Manufacturer (%d bytes): %s\n"
+ "Model number (%d bytes): %s\n"
+ "Serial number (%d bytes): %s\n"
+ "Primary device type: \n"
+ " Category: %d \n"
+ " OUI: %02x:%02x:%02x \n"
+ " OUI Subdivision: %u \n",
+ (int)strlen(info->name), info->name,
+ (int)strlen(info->model_name), info->model_name,
+ (int)strlen(info->manufacturer), info->manufacturer,
+ (int)strlen(info->model_nr), info->model_nr,
+ (int)strlen(info->serial), info->serial,
+ info->prim_dev_type.category,
+ info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1],
+ info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv);
+ _skb = dev_alloc_skb(sizeof(*_d1)
+ + sizeof(struct wlp_attr_uuid_e)
+ + sizeof(struct wlp_attr_wss_sel_mthd)
+ + sizeof(struct wlp_attr_dev_name)
+ + strlen(info->name)
+ + sizeof(struct wlp_attr_manufacturer)
+ + strlen(info->manufacturer)
+ + sizeof(struct wlp_attr_model_name)
+ + strlen(info->model_name)
+ + sizeof(struct wlp_attr_model_nr)
+ + strlen(info->model_nr)
+ + sizeof(struct wlp_attr_serial)
+ + strlen(info->serial)
+ + sizeof(struct wlp_attr_prim_dev_type)
+ + sizeof(struct wlp_attr_wlp_assc_err));
+ if (_skb == NULL) {
+ dev_err(dev, "WLP: Cannot allocate memory for association "
+ "message.\n");
+ result = -ENOMEM;
+ goto error;
+ }
+ _d1 = (void *) _skb->data;
+ d_printf(6, dev, "D1 starts at %p \n", _d1);
+ _d1->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
+ _d1->hdr.type = WLP_FRAME_ASSOCIATION;
+ _d1->type = WLP_ASSOC_D1;
+
+ wlp_set_version(&_d1->version, WLP_VERSION);
+ wlp_set_msg_type(&_d1->msg_type, WLP_ASSOC_D1);
+ d1_itr = _d1->attr;
+ used = wlp_set_uuid_e(d1_itr, &wlp->uuid);
+ used += wlp_set_wss_sel_mthd(d1_itr + used, WLP_WSS_REG_SELECT);
+ used += wlp_set_dev_name(d1_itr + used, info->name,
+ strlen(info->name));
+ used += wlp_set_manufacturer(d1_itr + used, info->manufacturer,
+ strlen(info->manufacturer));
+ used += wlp_set_model_name(d1_itr + used, info->model_name,
+ strlen(info->model_name));
+ used += wlp_set_model_nr(d1_itr + used, info->model_nr,
+ strlen(info->model_nr));
+ used += wlp_set_serial(d1_itr + used, info->serial,
+ strlen(info->serial));
+ used += wlp_set_prim_dev_type(d1_itr + used, &info->prim_dev_type);
+ used += wlp_set_wlp_assc_err(d1_itr + used, WLP_ASSOC_ERROR_NONE);
+ skb_put(_skb, sizeof(*_d1) + used);
+ d_printf(6, dev, "D1 message:\n");
+ d_dump(6, dev, _d1, sizeof(*_d1)
+ + sizeof(struct wlp_attr_uuid_e)
+ + sizeof(struct wlp_attr_wss_sel_mthd)
+ + sizeof(struct wlp_attr_dev_name)
+ + strlen(info->name)
+ + sizeof(struct wlp_attr_manufacturer)
+ + strlen(info->manufacturer)
+ + sizeof(struct wlp_attr_model_name)
+ + strlen(info->model_name)
+ + sizeof(struct wlp_attr_model_nr)
+ + strlen(info->model_nr)
+ + sizeof(struct wlp_attr_serial)
+ + strlen(info->serial)
+ + sizeof(struct wlp_attr_prim_dev_type)
+ + sizeof(struct wlp_attr_wlp_assc_err));
+ *skb = _skb;
+error:
+ d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result);
+ return result;
+}
+
+/**
+ * Construct a D2 association frame
+ *
+ * We use the radio control functions to determine the values of the device
+ * properties. These are of variable length and the total space needed is
+ * tallied first before we start constructing the message. The radio
+ * control functions return strings that are terminated with \0. This
+ * character should not be included in the message (there is a length field
+ * accompanying it in the attribute).
+ */
+static
+int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss,
+ struct sk_buff **skb, struct wlp_uuid *uuid_e)
+{
+
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = 0;
+ struct wlp_device_info *info;
+ size_t used = 0;
+ struct wlp_frame_assoc *_d2;
+ struct sk_buff *_skb;
+ void *d2_itr;
+ size_t mem_needed;
+
+ d_fnstart(6, dev, "wlp %p\n", wlp);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_setup_device_info(wlp);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to setup device "
+ "information for D2 message.\n");
+ goto error;
+ }
+ }
+ info = wlp->dev_info;
+ d_printf(6, dev, "Local properties:\n"
+ "Device name (%d bytes): %s\n"
+ "Model name (%d bytes): %s\n"
+ "Manufacturer (%d bytes): %s\n"
+ "Model number (%d bytes): %s\n"
+ "Serial number (%d bytes): %s\n"
+ "Primary device type: \n"
+ " Category: %d \n"
+ " OUI: %02x:%02x:%02x \n"
+ " OUI Subdivision: %u \n",
+ (int)strlen(info->name), info->name,
+ (int)strlen(info->model_name), info->model_name,
+ (int)strlen(info->manufacturer), info->manufacturer,
+ (int)strlen(info->model_nr), info->model_nr,
+ (int)strlen(info->serial), info->serial,
+ info->prim_dev_type.category,
+ info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1],
+ info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv);
+ mem_needed = sizeof(*_d2)
+ + sizeof(struct wlp_attr_uuid_e)
+ + sizeof(struct wlp_attr_uuid_r)
+ + sizeof(struct wlp_attr_dev_name)
+ + strlen(info->name)
+ + sizeof(struct wlp_attr_manufacturer)
+ + strlen(info->manufacturer)
+ + sizeof(struct wlp_attr_model_name)
+ + strlen(info->model_name)
+ + sizeof(struct wlp_attr_model_nr)
+ + strlen(info->model_nr)
+ + sizeof(struct wlp_attr_serial)
+ + strlen(info->serial)
+ + sizeof(struct wlp_attr_prim_dev_type)
+ + sizeof(struct wlp_attr_wlp_assc_err);
+ if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
+ mem_needed += sizeof(struct wlp_attr_wss_info)
+ + sizeof(struct wlp_wss_info)
+ + strlen(wlp->wss.name);
+ _skb = dev_alloc_skb(mem_needed);
+ if (_skb == NULL) {
+ dev_err(dev, "WLP: Cannot allocate memory for association "
+ "message.\n");
+ result = -ENOMEM;
+ goto error;
+ }
+ _d2 = (void *) _skb->data;
+ d_printf(6, dev, "D2 starts at %p \n", _d2);
+ _d2->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
+ _d2->hdr.type = WLP_FRAME_ASSOCIATION;
+ _d2->type = WLP_ASSOC_D2;
+
+ wlp_set_version(&_d2->version, WLP_VERSION);
+ wlp_set_msg_type(&_d2->msg_type, WLP_ASSOC_D2);
+ d2_itr = _d2->attr;
+ used = wlp_set_uuid_e(d2_itr, uuid_e);
+ used += wlp_set_uuid_r(d2_itr + used, &wlp->uuid);
+ if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
+ used += wlp_set_wss_info(d2_itr + used, &wlp->wss);
+ used += wlp_set_dev_name(d2_itr + used, info->name,
+ strlen(info->name));
+ used += wlp_set_manufacturer(d2_itr + used, info->manufacturer,
+ strlen(info->manufacturer));
+ used += wlp_set_model_name(d2_itr + used, info->model_name,
+ strlen(info->model_name));
+ used += wlp_set_model_nr(d2_itr + used, info->model_nr,
+ strlen(info->model_nr));
+ used += wlp_set_serial(d2_itr + used, info->serial,
+ strlen(info->serial));
+ used += wlp_set_prim_dev_type(d2_itr + used, &info->prim_dev_type);
+ used += wlp_set_wlp_assc_err(d2_itr + used, WLP_ASSOC_ERROR_NONE);
+ skb_put(_skb, sizeof(*_d2) + used);
+ d_printf(6, dev, "D2 message:\n");
+ d_dump(6, dev, _d2, mem_needed);
+ *skb = _skb;
+error:
+ d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result);
+ return result;
+}
+
+/**
+ * Allocate memory for and populate fields of F0 association frame
+ *
+ * Currently (while focusing on unsecure enrollment) we ignore the
+ * nonce's that could be placed in the message. Only the error field is
+ * populated by the value provided by the caller.
+ */
+static
+int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb,
+ enum wlp_assc_error error)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = -ENOMEM;
+ struct {
+ struct wlp_frame_assoc f0_hdr;
+ struct wlp_attr_enonce enonce;
+ struct wlp_attr_rnonce rnonce;
+ struct wlp_attr_wlp_assc_err assc_err;
+ } *f0;
+ struct sk_buff *_skb;
+ struct wlp_nonce tmp;
+
+ d_fnstart(6, dev, "wlp %p\n", wlp);
+ _skb = dev_alloc_skb(sizeof(*f0));
+ if (_skb == NULL) {
+ dev_err(dev, "WLP: Unable to allocate memory for F0 "
+ "association frame. \n");
+ goto error_alloc;
+ }
+ f0 = (void *) _skb->data;
+ d_printf(6, dev, "F0 starts at %p \n", f0);
+ f0->f0_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
+ f0->f0_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
+ f0->f0_hdr.type = WLP_ASSOC_F0;
+ wlp_set_version(&f0->f0_hdr.version, WLP_VERSION);
+ wlp_set_msg_type(&f0->f0_hdr.msg_type, WLP_ASSOC_F0);
+ memset(&tmp, 0, sizeof(tmp));
+ wlp_set_enonce(&f0->enonce, &tmp);
+ wlp_set_rnonce(&f0->rnonce, &tmp);
+ wlp_set_wlp_assc_err(&f0->assc_err, error);
+ skb_put(_skb, sizeof(*f0));
+ *skb = _skb;
+ result = 0;
+error_alloc:
+ d_fnend(6, dev, "wlp %p, result %d \n", wlp, result);
+ return result;
+}
+
+/**
+ * Parse F0 frame
+ *
+ * We just retrieve the values and print it as an error to the user.
+ * Calling function already knows an error occured (F0 indicates error), so
+ * we just parse the content as debug for higher layers.
+ */
+int wlp_parse_f0(struct wlp *wlp, struct sk_buff *skb)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_frame_assoc *f0 = (void *) skb->data;
+ void *ptr = skb->data;
+ size_t len = skb->len;
+ size_t used;
+ ssize_t result;
+ struct wlp_nonce enonce, rnonce;
+ enum wlp_assc_error assc_err;
+ char enonce_buf[WLP_WSS_NONCE_STRSIZE];
+ char rnonce_buf[WLP_WSS_NONCE_STRSIZE];
+
+ used = sizeof(*f0);
+ result = wlp_get_enonce(wlp, ptr + used, &enonce, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain Enrollee nonce "
+ "attribute from F0 message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_rnonce(wlp, ptr + used, &rnonce, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain Registrar nonce "
+ "attribute from F0 message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WLP Association error "
+ "attribute from F0 message.\n");
+ goto error_parse;
+ }
+ wlp_wss_nonce_print(enonce_buf, sizeof(enonce_buf), &enonce);
+ wlp_wss_nonce_print(rnonce_buf, sizeof(rnonce_buf), &rnonce);
+ dev_err(dev, "WLP: Received F0 error frame from neighbor. Enrollee "
+ "nonce: %s, Registrar nonce: %s, WLP Association error: %s.\n",
+ enonce_buf, rnonce_buf, wlp_assc_error_str(assc_err));
+ result = 0;
+error_parse:
+ return result;
+}
+
+/**
+ * Retrieve variable device information from association message
+ *
+ * The device information parsed is not required in any message. This
+ * routine will thus not fail if an attribute is not present.
+ * The attributes are expected in a certain order, even if all are not
+ * present. The "attribute type" value is used to ensure the attributes
+ * are parsed in the correct order.
+ *
+ * If an error is encountered during parsing the function will return an
+ * error code, when this happens the given device_info structure may be
+ * partially filled.
+ */
+static
+int wlp_get_variable_info(struct wlp *wlp, void *data,
+ struct wlp_device_info *dev_info, ssize_t len)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ size_t used = 0;
+ struct wlp_attr_hdr *hdr;
+ ssize_t result = 0;
+ unsigned last = 0;
+
+ while (len - used > 0) {
+ if (len - used < sizeof(*hdr)) {
+ dev_err(dev, "WLP: Partial data in frame, cannot "
+ "parse. \n");
+ goto error_parse;
+ }
+ hdr = data + used;
+ switch (le16_to_cpu(hdr->type)) {
+ case WLP_ATTR_MANUF:
+ if (last >= WLP_ATTR_MANUF) {
+ dev_err(dev, "WLP: Incorrect order of "
+ "attribute values in D1 msg.\n");
+ goto error_parse;
+ }
+ result = wlp_get_manufacturer(wlp, data + used,
+ dev_info->manufacturer,
+ len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to obtain "
+ "Manufacturer attribute from D1 "
+ "message.\n");
+ goto error_parse;
+ }
+ last = WLP_ATTR_MANUF;
+ used += result;
+ break;
+ case WLP_ATTR_MODEL_NAME:
+ if (last >= WLP_ATTR_MODEL_NAME) {
+ dev_err(dev, "WLP: Incorrect order of "
+ "attribute values in D1 msg.\n");
+ goto error_parse;
+ }
+ result = wlp_get_model_name(wlp, data + used,
+ dev_info->model_name,
+ len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to obtain Model "
+ "name attribute from D1 message.\n");
+ goto error_parse;
+ }
+ last = WLP_ATTR_MODEL_NAME;
+ used += result;
+ break;
+ case WLP_ATTR_MODEL_NR:
+ if (last >= WLP_ATTR_MODEL_NR) {
+ dev_err(dev, "WLP: Incorrect order of "
+ "attribute values in D1 msg.\n");
+ goto error_parse;
+ }
+ result = wlp_get_model_nr(wlp, data + used,
+ dev_info->model_nr,
+ len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to obtain Model "
+ "number attribute from D1 message.\n");
+ goto error_parse;
+ }
+ last = WLP_ATTR_MODEL_NR;
+ used += result;
+ break;
+ case WLP_ATTR_SERIAL:
+ if (last >= WLP_ATTR_SERIAL) {
+ dev_err(dev, "WLP: Incorrect order of "
+ "attribute values in D1 msg.\n");
+ goto error_parse;
+ }
+ result = wlp_get_serial(wlp, data + used,
+ dev_info->serial, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to obtain Serial "
+ "number attribute from D1 message.\n");
+ goto error_parse;
+ }
+ last = WLP_ATTR_SERIAL;
+ used += result;
+ break;
+ case WLP_ATTR_PRI_DEV_TYPE:
+ if (last >= WLP_ATTR_PRI_DEV_TYPE) {
+ dev_err(dev, "WLP: Incorrect order of "
+ "attribute values in D1 msg.\n");
+ goto error_parse;
+ }
+ result = wlp_get_prim_dev_type(wlp, data + used,
+ &dev_info->prim_dev_type,
+ len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to obtain Primary "
+ "device type attribute from D1 "
+ "message.\n");
+ goto error_parse;
+ }
+ dev_info->prim_dev_type.category =
+ le16_to_cpu(dev_info->prim_dev_type.category);
+ dev_info->prim_dev_type.subID =
+ le16_to_cpu(dev_info->prim_dev_type.subID);
+ last = WLP_ATTR_PRI_DEV_TYPE;
+ used += result;
+ break;
+ default:
+ /* This is not variable device information. */
+ goto out;
+ break;
+ }
+ }
+out:
+ return used;
+error_parse:
+ return -EINVAL;
+}
+
+/**
+ * Parse incoming D1 frame, populate attribute values
+ *
+ * Caller provides pointers to memory already allocated for attributes
+ * expected in the D1 frame. These variables will be populated.
+ */
+static
+int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb,
+ struct wlp_uuid *uuid_e,
+ enum wlp_wss_sel_mthd *sel_mthd,
+ struct wlp_device_info *dev_info,
+ enum wlp_assc_error *assc_err)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_frame_assoc *d1 = (void *) skb->data;
+ void *ptr = skb->data;
+ size_t len = skb->len;
+ size_t used;
+ ssize_t result;
+
+ used = sizeof(*d1);
+ result = wlp_get_uuid_e(wlp, ptr + used, uuid_e, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain UUID-E attribute from D1 "
+ "message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_wss_sel_mthd(wlp, ptr + used, sel_mthd, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSS selection method "
+ "from D1 message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_dev_name(wlp, ptr + used, dev_info->name,
+ len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain Device Name from D1 "
+ "message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_variable_info(wlp, ptr + used, dev_info, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain Device Information from "
+ "D1 message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_wlp_assc_err(wlp, ptr + used, assc_err, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WLP Association Error "
+ "Information from D1 message.\n");
+ goto error_parse;
+ }
+ result = 0;
+error_parse:
+ return result;
+}
+/**
+ * Handle incoming D1 frame
+ *
+ * The frame has already been verified to contain an Association header with
+ * the correct version number. Parse the incoming frame, construct and send
+ * a D2 frame in response.
+ *
+ * It is not clear what to do with most fields in the incoming D1 frame. We
+ * retrieve and discard the information here for now.
+ */
+void wlp_handle_d1_frame(struct work_struct *ws)
+{
+ struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
+ struct wlp_assoc_frame_ctx,
+ ws);
+ struct wlp *wlp = frame_ctx->wlp;
+ struct wlp_wss *wss = &wlp->wss;
+ struct sk_buff *skb = frame_ctx->skb;
+ struct uwb_dev_addr *src = &frame_ctx->src;
+ int result;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_uuid uuid_e;
+ enum wlp_wss_sel_mthd sel_mthd = 0;
+ struct wlp_device_info dev_info;
+ enum wlp_assc_error assc_err;
+ char uuid[WLP_WSS_UUID_STRSIZE];
+ struct sk_buff *resp = NULL;
+
+ /* Parse D1 frame */
+ d_fnstart(6, dev, "WLP: handle D1 frame. wlp = %p, skb = %p\n",
+ wlp, skb);
+ mutex_lock(&wss->mutex);
+ mutex_lock(&wlp->mutex); /* to access wlp->uuid */
+ memset(&dev_info, 0, sizeof(dev_info));
+ result = wlp_parse_d1_frame(wlp, skb, &uuid_e, &sel_mthd, &dev_info,
+ &assc_err);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to parse incoming D1 frame.\n");
+ kfree_skb(skb);
+ goto out;
+ }
+ wlp_wss_uuid_print(uuid, sizeof(uuid), &uuid_e);
+ d_printf(6, dev, "From D1 frame:\n"
+ "UUID-E: %s\n"
+ "Selection method: %d\n"
+ "Device name (%d bytes): %s\n"
+ "Model name (%d bytes): %s\n"
+ "Manufacturer (%d bytes): %s\n"
+ "Model number (%d bytes): %s\n"
+ "Serial number (%d bytes): %s\n"
+ "Primary device type: \n"
+ " Category: %d \n"
+ " OUI: %02x:%02x:%02x \n"
+ " OUI Subdivision: %u \n",
+ uuid, sel_mthd,
+ (int)strlen(dev_info.name), dev_info.name,
+ (int)strlen(dev_info.model_name), dev_info.model_name,
+ (int)strlen(dev_info.manufacturer), dev_info.manufacturer,
+ (int)strlen(dev_info.model_nr), dev_info.model_nr,
+ (int)strlen(dev_info.serial), dev_info.serial,
+ dev_info.prim_dev_type.category,
+ dev_info.prim_dev_type.OUI[0],
+ dev_info.prim_dev_type.OUI[1],
+ dev_info.prim_dev_type.OUI[2],
+ dev_info.prim_dev_type.OUIsubdiv);
+
+ kfree_skb(skb);
+ if (!wlp_uuid_is_set(&wlp->uuid)) {
+ dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
+ "proceed. Respong to D1 message with error F0.\n");
+ result = wlp_build_assoc_f0(wlp, &resp,
+ WLP_ASSOC_ERROR_NOT_READY);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to construct F0 message.\n");
+ goto out;
+ }
+ } else {
+ /* Construct D2 frame */
+ result = wlp_build_assoc_d2(wlp, wss, &resp, &uuid_e);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to construct D2 message.\n");
+ goto out;
+ }
+ }
+ /* Send D2 frame */
+ BUG_ON(wlp->xmit_frame == NULL);
+ result = wlp->xmit_frame(wlp, resp, src);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to transmit D2 association "
+ "message: %d\n", result);
+ if (result == -ENXIO)
+ dev_err(dev, "WLP: Is network interface up? \n");
+ /* We could try again ... */
+ dev_kfree_skb_any(resp); /* we need to free if tx fails */
+ }
+out:
+ kfree(frame_ctx);
+ mutex_unlock(&wlp->mutex);
+ mutex_unlock(&wss->mutex);
+ d_fnend(6, dev, "WLP: handle D1 frame. wlp = %p\n", wlp);
+}
+
+/**
+ * Parse incoming D2 frame, create and populate temporary cache
+ *
+ * @skb: socket buffer in which D2 frame can be found
+ * @neighbor: the neighbor that sent the D2 frame
+ *
+ * Will allocate memory for temporary storage of information learned during
+ * discovery.
+ */
+int wlp_parse_d2_frame_to_cache(struct wlp *wlp, struct sk_buff *skb,
+ struct wlp_neighbor_e *neighbor)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_frame_assoc *d2 = (void *) skb->data;
+ void *ptr = skb->data;
+ size_t len = skb->len;
+ size_t used;
+ ssize_t result;
+ struct wlp_uuid uuid_e;
+ struct wlp_device_info *nb_info;
+ enum wlp_assc_error assc_err;
+
+ used = sizeof(*d2);
+ result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
+ "message.\n");
+ goto error_parse;
+ }
+ if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
+ dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
+ "local UUID sent in D1. \n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_uuid_r(wlp, ptr + used, &neighbor->uuid, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
+ "message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_wss_info_to_cache(wlp, ptr + used, neighbor,
+ len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSS information "
+ "from D2 message.\n");
+ goto error_parse;
+ }
+ used += result;
+ neighbor->info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
+ if (neighbor->info == NULL) {
+ dev_err(dev, "WLP: cannot allocate memory to store device "
+ "info.\n");
+ result = -ENOMEM;
+ goto error_parse;
+ }
+ nb_info = neighbor->info;
+ result = wlp_get_dev_name(wlp, ptr + used, nb_info->name,
+ len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain Device Name from D2 "
+ "message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_variable_info(wlp, ptr + used, nb_info, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain Device Information from "
+ "D2 message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WLP Association Error "
+ "Information from D2 message.\n");
+ goto error_parse;
+ }
+ if (assc_err != WLP_ASSOC_ERROR_NONE) {
+ dev_err(dev, "WLP: neighbor device returned association "
+ "error %d\n", assc_err);
+ result = -EINVAL;
+ goto error_parse;
+ }
+ result = 0;
+error_parse:
+ if (result < 0)
+ wlp_remove_neighbor_tmp_info(neighbor);
+ return result;
+}
+
+/**
+ * Parse incoming D2 frame, populate attribute values of WSS bein enrolled in
+ *
+ * @wss: our WSS that will be enrolled
+ * @skb: socket buffer in which D2 frame can be found
+ * @neighbor: the neighbor that sent the D2 frame
+ * @wssid: the wssid of the WSS in which we want to enroll
+ *
+ * Forms part of enrollment sequence. We are trying to enroll in WSS with
+ * @wssid by using @neighbor as registrar. A D1 message was sent to
+ * @neighbor and now we need to parse the D2 response. The neighbor's
+ * response is searched for the requested WSS and if found (and it accepts
+ * enrollment), we store the information.
+ */
+int wlp_parse_d2_frame_to_enroll(struct wlp_wss *wss, struct sk_buff *skb,
+ struct wlp_neighbor_e *neighbor,
+ struct wlp_uuid *wssid)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ void *ptr = skb->data;
+ size_t len = skb->len;
+ size_t used;
+ ssize_t result;
+ struct wlp_uuid uuid_e;
+ struct wlp_uuid uuid_r;
+ struct wlp_device_info nb_info;
+ enum wlp_assc_error assc_err;
+ char uuid_bufA[WLP_WSS_UUID_STRSIZE];
+ char uuid_bufB[WLP_WSS_UUID_STRSIZE];
+
+ used = sizeof(struct wlp_frame_assoc);
+ result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
+ "message.\n");
+ goto error_parse;
+ }
+ if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
+ dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
+ "local UUID sent in D1. \n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_uuid_r(wlp, ptr + used, &uuid_r, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
+ "message.\n");
+ goto error_parse;
+ }
+ if (memcmp(&uuid_r, &neighbor->uuid, sizeof(uuid_r))) {
+ wlp_wss_uuid_print(uuid_bufA, sizeof(uuid_bufA),
+ &neighbor->uuid);
+ wlp_wss_uuid_print(uuid_bufB, sizeof(uuid_bufB), &uuid_r);
+ dev_err(dev, "WLP: UUID of neighbor does not match UUID "
+ "learned during discovery. Originally discovered: %s, "
+ "now from D2 message: %s\n", uuid_bufA, uuid_bufB);
+ result = -EINVAL;
+ goto error_parse;
+ }
+ used += result;
+ wss->wssid = *wssid;
+ result = wlp_get_wss_info_to_enroll(wlp, ptr + used, wss, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSS information "
+ "from D2 message.\n");
+ goto error_parse;
+ }
+ if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
+ dev_err(dev, "WLP: D2 message did not contain information "
+ "for successful enrollment. \n");
+ result = -EINVAL;
+ goto error_parse;
+ }
+ used += result;
+ /* Place device information on stack to continue parsing of message */
+ result = wlp_get_dev_name(wlp, ptr + used, nb_info.name,
+ len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain Device Name from D2 "
+ "message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_variable_info(wlp, ptr + used, &nb_info, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain Device Information from "
+ "D2 message.\n");
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WLP Association Error "
+ "Information from D2 message.\n");
+ goto error_parse;
+ }
+ if (assc_err != WLP_ASSOC_ERROR_NONE) {
+ dev_err(dev, "WLP: neighbor device returned association "
+ "error %d\n", assc_err);
+ if (wss->state == WLP_WSS_STATE_PART_ENROLLED) {
+ dev_err(dev, "WLP: Enrolled in WSS (should not "
+ "happen according to spec). Undoing. \n");
+ wlp_wss_reset(wss);
+ }
+ result = -EINVAL;
+ goto error_parse;
+ }
+ result = 0;
+error_parse:
+ return result;
+}
+
+/**
+ * Parse C3/C4 frame into provided variables
+ *
+ * @wssid: will point to copy of wssid retrieved from C3/C4 frame
+ * @tag: will point to copy of tag retrieved from C3/C4 frame
+ * @virt_addr: will point to copy of virtual address retrieved from C3/C4
+ * frame.
+ *
+ * Calling function has to allocate memory for these values.
+ *
+ * skb contains a valid C3/C4 frame, return the individual fields of this
+ * frame in the provided variables.
+ */
+int wlp_parse_c3c4_frame(struct wlp *wlp, struct sk_buff *skb,
+ struct wlp_uuid *wssid, u8 *tag,
+ struct uwb_mac_addr *virt_addr)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result;
+ void *ptr = skb->data;
+ size_t len = skb->len;
+ size_t used;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ struct wlp_frame_assoc *assoc = ptr;
+
+ d_fnstart(6, dev, "wlp %p, skb %p \n", wlp, skb);
+ used = sizeof(*assoc);
+ result = wlp_get_wssid(wlp, ptr + used, wssid, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSSID attribute from "
+ "%s message.\n", wlp_assoc_frame_str(assoc->type));
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_wss_tag(wlp, ptr + used, tag, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSS tag attribute from "
+ "%s message.\n", wlp_assoc_frame_str(assoc->type));
+ goto error_parse;
+ }
+ used += result;
+ result = wlp_get_wss_virt(wlp, ptr + used, virt_addr, len - used);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSS virtual address "
+ "attribute from %s message.\n",
+ wlp_assoc_frame_str(assoc->type));
+ goto error_parse;
+ }
+ wlp_wss_uuid_print(buf, sizeof(buf), wssid);
+ d_printf(6, dev, "WLP: parsed: WSSID %s, tag 0x%02x, virt "
+ "%02x:%02x:%02x:%02x:%02x:%02x \n", buf, *tag,
+ virt_addr->data[0], virt_addr->data[1], virt_addr->data[2],
+ virt_addr->data[3], virt_addr->data[4], virt_addr->data[5]);
+
+error_parse:
+ d_fnend(6, dev, "wlp %p, skb %p, result = %d \n", wlp, skb, result);
+ return result;
+}
+
+/**
+ * Allocate memory for and populate fields of C1 or C2 association frame
+ *
+ * The C1 and C2 association frames appear identical - except for the type.
+ */
+static
+int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss,
+ struct sk_buff **skb, enum wlp_assoc_type type)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = -ENOMEM;
+ struct {
+ struct wlp_frame_assoc c_hdr;
+ struct wlp_attr_wssid wssid;
+ } *c;
+ struct sk_buff *_skb;
+
+ d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss);
+ _skb = dev_alloc_skb(sizeof(*c));
+ if (_skb == NULL) {
+ dev_err(dev, "WLP: Unable to allocate memory for C1/C2 "
+ "association frame. \n");
+ goto error_alloc;
+ }
+ c = (void *) _skb->data;
+ d_printf(6, dev, "C1/C2 starts at %p \n", c);
+ c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
+ c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
+ c->c_hdr.type = type;
+ wlp_set_version(&c->c_hdr.version, WLP_VERSION);
+ wlp_set_msg_type(&c->c_hdr.msg_type, type);
+ wlp_set_wssid(&c->wssid, &wss->wssid);
+ skb_put(_skb, sizeof(*c));
+ d_printf(6, dev, "C1/C2 message:\n");
+ d_dump(6, dev, c, sizeof(*c));
+ *skb = _skb;
+ result = 0;
+error_alloc:
+ d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result);
+ return result;
+}
+
+
+static
+int wlp_build_assoc_c1(struct wlp *wlp, struct wlp_wss *wss,
+ struct sk_buff **skb)
+{
+ return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C1);
+}
+
+static
+int wlp_build_assoc_c2(struct wlp *wlp, struct wlp_wss *wss,
+ struct sk_buff **skb)
+{
+ return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C2);
+}
+
+
+/**
+ * Allocate memory for and populate fields of C3 or C4 association frame
+ *
+ * The C3 and C4 association frames appear identical - except for the type.
+ */
+static
+int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss,
+ struct sk_buff **skb, enum wlp_assoc_type type)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = -ENOMEM;
+ struct {
+ struct wlp_frame_assoc c_hdr;
+ struct wlp_attr_wssid wssid;
+ struct wlp_attr_wss_tag wss_tag;
+ struct wlp_attr_wss_virt wss_virt;
+ } *c;
+ struct sk_buff *_skb;
+
+ d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss);
+ _skb = dev_alloc_skb(sizeof(*c));
+ if (_skb == NULL) {
+ dev_err(dev, "WLP: Unable to allocate memory for C3/C4 "
+ "association frame. \n");
+ goto error_alloc;
+ }
+ c = (void *) _skb->data;
+ d_printf(6, dev, "C3/C4 starts at %p \n", c);
+ c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
+ c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
+ c->c_hdr.type = type;
+ wlp_set_version(&c->c_hdr.version, WLP_VERSION);
+ wlp_set_msg_type(&c->c_hdr.msg_type, type);
+ wlp_set_wssid(&c->wssid, &wss->wssid);
+ wlp_set_wss_tag(&c->wss_tag, wss->tag);
+ wlp_set_wss_virt(&c->wss_virt, &wss->virtual_addr);
+ skb_put(_skb, sizeof(*c));
+ d_printf(6, dev, "C3/C4 message:\n");
+ d_dump(6, dev, c, sizeof(*c));
+ *skb = _skb;
+ result = 0;
+error_alloc:
+ d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result);
+ return result;
+}
+
+static
+int wlp_build_assoc_c3(struct wlp *wlp, struct wlp_wss *wss,
+ struct sk_buff **skb)
+{
+ return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C3);
+}
+
+static
+int wlp_build_assoc_c4(struct wlp *wlp, struct wlp_wss *wss,
+ struct sk_buff **skb)
+{
+ return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C4);
+}
+
+
+#define wlp_send_assoc(type, id) \
+static int wlp_send_assoc_##type(struct wlp *wlp, struct wlp_wss *wss, \
+ struct uwb_dev_addr *dev_addr) \
+{ \
+ struct device *dev = &wlp->rc->uwb_dev.dev; \
+ int result; \
+ struct sk_buff *skb = NULL; \
+ d_fnstart(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \
+ wlp, wss, dev_addr->data[1], dev_addr->data[0]); \
+ d_printf(6, dev, "WLP: Constructing %s frame. \n", \
+ wlp_assoc_frame_str(id)); \
+ /* Build the frame */ \
+ result = wlp_build_assoc_##type(wlp, wss, &skb); \
+ if (result < 0) { \
+ dev_err(dev, "WLP: Unable to construct %s association " \
+ "frame: %d\n", wlp_assoc_frame_str(id), result);\
+ goto error_build_assoc; \
+ } \
+ /* Send the frame */ \
+ d_printf(6, dev, "Transmitting %s frame to %02x:%02x \n", \
+ wlp_assoc_frame_str(id), \
+ dev_addr->data[1], dev_addr->data[0]); \
+ BUG_ON(wlp->xmit_frame == NULL); \
+ result = wlp->xmit_frame(wlp, skb, dev_addr); \
+ if (result < 0) { \
+ dev_err(dev, "WLP: Unable to transmit %s association " \
+ "message: %d\n", wlp_assoc_frame_str(id), \
+ result); \
+ if (result == -ENXIO) \
+ dev_err(dev, "WLP: Is network interface " \
+ "up? \n"); \
+ goto error_xmit; \
+ } \
+ return 0; \
+error_xmit: \
+ /* We could try again ... */ \
+ dev_kfree_skb_any(skb);/*we need to free if tx fails*/ \
+error_build_assoc: \
+ d_fnend(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \
+ wlp, wss, dev_addr->data[1], dev_addr->data[0]); \
+ return result; \
+}
+
+wlp_send_assoc(d1, WLP_ASSOC_D1)
+wlp_send_assoc(c1, WLP_ASSOC_C1)
+wlp_send_assoc(c3, WLP_ASSOC_C3)
+
+int wlp_send_assoc_frame(struct wlp *wlp, struct wlp_wss *wss,
+ struct uwb_dev_addr *dev_addr,
+ enum wlp_assoc_type type)
+{
+ int result = 0;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ switch (type) {
+ case WLP_ASSOC_D1:
+ result = wlp_send_assoc_d1(wlp, wss, dev_addr);
+ break;
+ case WLP_ASSOC_C1:
+ result = wlp_send_assoc_c1(wlp, wss, dev_addr);
+ break;
+ case WLP_ASSOC_C3:
+ result = wlp_send_assoc_c3(wlp, wss, dev_addr);
+ break;
+ default:
+ dev_err(dev, "WLP: Received request to send unknown "
+ "association message.\n");
+ result = -EINVAL;
+ break;
+ }
+ return result;
+}
+
+/**
+ * Handle incoming C1 frame
+ *
+ * The frame has already been verified to contain an Association header with
+ * the correct version number. Parse the incoming frame, construct and send
+ * a C2 frame in response.
+ */
+void wlp_handle_c1_frame(struct work_struct *ws)
+{
+ struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
+ struct wlp_assoc_frame_ctx,
+ ws);
+ struct wlp *wlp = frame_ctx->wlp;
+ struct wlp_wss *wss = &wlp->wss;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_frame_assoc *c1 = (void *) frame_ctx->skb->data;
+ unsigned int len = frame_ctx->skb->len;
+ struct uwb_dev_addr *src = &frame_ctx->src;
+ int result;
+ struct wlp_uuid wssid;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ struct sk_buff *resp = NULL;
+
+ /* Parse C1 frame */
+ d_fnstart(6, dev, "WLP: handle C1 frame. wlp = %p, c1 = %p\n",
+ wlp, c1);
+ mutex_lock(&wss->mutex);
+ result = wlp_get_wssid(wlp, (void *)c1 + sizeof(*c1), &wssid,
+ len - sizeof(*c1));
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSSID from C1 frame.\n");
+ goto out;
+ }
+ wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
+ d_printf(6, dev, "Received C1 frame with WSSID %s \n", buf);
+ if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
+ && wss->state == WLP_WSS_STATE_ACTIVE) {
+ d_printf(6, dev, "WSSID from C1 frame is known locally "
+ "and is active\n");
+ /* Construct C2 frame */
+ result = wlp_build_assoc_c2(wlp, wss, &resp);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to construct C2 message.\n");
+ goto out;
+ }
+ } else {
+ d_printf(6, dev, "WSSID from C1 frame is not known locally "
+ "or is not active\n");
+ /* Construct F0 frame */
+ result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to construct F0 message.\n");
+ goto out;
+ }
+ }
+ /* Send C2 frame */
+ d_printf(6, dev, "Transmitting response (C2/F0) frame to %02x:%02x \n",
+ src->data[1], src->data[0]);
+ BUG_ON(wlp->xmit_frame == NULL);
+ result = wlp->xmit_frame(wlp, resp, src);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to transmit response association "
+ "message: %d\n", result);
+ if (result == -ENXIO)
+ dev_err(dev, "WLP: Is network interface up? \n");
+ /* We could try again ... */
+ dev_kfree_skb_any(resp); /* we need to free if tx fails */
+ }
+out:
+ kfree_skb(frame_ctx->skb);
+ kfree(frame_ctx);
+ mutex_unlock(&wss->mutex);
+ d_fnend(6, dev, "WLP: handle C1 frame. wlp = %p\n", wlp);
+}
+
+/**
+ * Handle incoming C3 frame
+ *
+ * The frame has already been verified to contain an Association header with
+ * the correct version number. Parse the incoming frame, construct and send
+ * a C4 frame in response. If the C3 frame identifies a WSS that is locally
+ * active then we connect to this neighbor (add it to our EDA cache).
+ */
+void wlp_handle_c3_frame(struct work_struct *ws)
+{
+ struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
+ struct wlp_assoc_frame_ctx,
+ ws);
+ struct wlp *wlp = frame_ctx->wlp;
+ struct wlp_wss *wss = &wlp->wss;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct sk_buff *skb = frame_ctx->skb;
+ struct uwb_dev_addr *src = &frame_ctx->src;
+ int result;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ struct sk_buff *resp = NULL;
+ struct wlp_uuid wssid;
+ u8 tag;
+ struct uwb_mac_addr virt_addr;
+
+ /* Parse C3 frame */
+ d_fnstart(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n",
+ wlp, skb);
+ mutex_lock(&wss->mutex);
+ result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr);
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain values from C3 frame.\n");
+ goto out;
+ }
+ wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
+ d_printf(6, dev, "Received C3 frame with WSSID %s \n", buf);
+ if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
+ && wss->state >= WLP_WSS_STATE_ACTIVE) {
+ d_printf(6, dev, "WSSID from C3 frame is known locally "
+ "and is active\n");
+ result = wlp_eda_update_node(&wlp->eda, src, wss,
+ (void *) virt_addr.data, tag,
+ WLP_WSS_CONNECTED);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to update EDA cache "
+ "with new connected neighbor information.\n");
+ result = wlp_build_assoc_f0(wlp, &resp,
+ WLP_ASSOC_ERROR_INT);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to construct F0 "
+ "message.\n");
+ goto out;
+ }
+ } else {
+ wss->state = WLP_WSS_STATE_CONNECTED;
+ /* Construct C4 frame */
+ result = wlp_build_assoc_c4(wlp, wss, &resp);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to construct C4 "
+ "message.\n");
+ goto out;
+ }
+ }
+ } else {
+ d_printf(6, dev, "WSSID from C3 frame is not known locally "
+ "or is not active\n");
+ /* Construct F0 frame */
+ result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to construct F0 message.\n");
+ goto out;
+ }
+ }
+ /* Send C4 frame */
+ d_printf(6, dev, "Transmitting response (C4/F0) frame to %02x:%02x \n",
+ src->data[1], src->data[0]);
+ BUG_ON(wlp->xmit_frame == NULL);
+ result = wlp->xmit_frame(wlp, resp, src);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to transmit response association "
+ "message: %d\n", result);
+ if (result == -ENXIO)
+ dev_err(dev, "WLP: Is network interface up? \n");
+ /* We could try again ... */
+ dev_kfree_skb_any(resp); /* we need to free if tx fails */
+ }
+out:
+ kfree_skb(frame_ctx->skb);
+ kfree(frame_ctx);
+ mutex_unlock(&wss->mutex);
+ d_fnend(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n",
+ wlp, skb);
+}
+
+
diff --git a/drivers/uwb/wlp/sysfs.c b/drivers/uwb/wlp/sysfs.c
new file mode 100644
index 00000000000..1bb9b1f97d4
--- /dev/null
+++ b/drivers/uwb/wlp/sysfs.c
@@ -0,0 +1,709 @@
+/*
+ * WiMedia Logical Link Control Protocol (WLP)
+ * sysfs functions
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Reinette Chatre <reinette.chatre@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.
+ *
+ *
+ * FIXME: Docs
+ *
+ */
+
+#include <linux/wlp.h>
+#include "wlp-internal.h"
+
+static
+size_t wlp_wss_wssid_e_print(char *buf, size_t bufsize,
+ struct wlp_wssid_e *wssid_e)
+{
+ size_t used = 0;
+ used += scnprintf(buf, bufsize, " WSS: ");
+ used += wlp_wss_uuid_print(buf + used, bufsize - used,
+ &wssid_e->wssid);
+
+ if (wssid_e->info != NULL) {
+ used += scnprintf(buf + used, bufsize - used, " ");
+ used += uwb_mac_addr_print(buf + used, bufsize - used,
+ &wssid_e->info->bcast);
+ used += scnprintf(buf + used, bufsize - used, " %u %u %s\n",
+ wssid_e->info->accept_enroll,
+ wssid_e->info->sec_status,
+ wssid_e->info->name);
+ }
+ return used;
+}
+
+/**
+ * Print out information learned from neighbor discovery
+ *
+ * Some fields being printed may not be included in the device discovery
+ * information (it is not mandatory). We are thus careful how the
+ * information is printed to ensure it is clear to the user what field is
+ * being referenced.
+ * The information being printed is for one time use - temporary storage is
+ * cleaned after it is printed.
+ *
+ * Ideally sysfs output should be on one line. The information printed here
+ * contain a few strings so it will be hard to parse if they are all
+ * printed on the same line - without agreeing on a standard field
+ * separator.
+ */
+static
+ssize_t wlp_wss_neighborhood_print_remove(struct wlp *wlp, char *buf,
+ size_t bufsize)
+{
+ size_t used = 0;
+ struct wlp_neighbor_e *neighb;
+ struct wlp_wssid_e *wssid_e;
+
+ mutex_lock(&wlp->nbmutex);
+ used = scnprintf(buf, bufsize, "#Neighbor information\n"
+ "#uuid dev_addr\n"
+ "# Device Name:\n# Model Name:\n# Manufacturer:\n"
+ "# Model Nr:\n# Serial:\n"
+ "# Pri Dev type: CategoryID OUI OUISubdiv "
+ "SubcategoryID\n"
+ "# WSS: WSSID WSS_name accept_enroll sec_status "
+ "bcast\n"
+ "# WSS: WSSID WSS_name accept_enroll sec_status "
+ "bcast\n\n");
+ list_for_each_entry(neighb, &wlp->neighbors, node) {
+ if (bufsize - used <= 0)
+ goto out;
+ used += wlp_wss_uuid_print(buf + used, bufsize - used,
+ &neighb->uuid);
+ buf[used++] = ' ';
+ used += uwb_dev_addr_print(buf + used, bufsize - used,
+ &neighb->uwb_dev->dev_addr);
+ if (neighb->info != NULL)
+ used += scnprintf(buf + used, bufsize - used,
+ "\n Device Name: %s\n"
+ " Model Name: %s\n"
+ " Manufacturer:%s \n"
+ " Model Nr: %s\n"
+ " Serial: %s\n"
+ " Pri Dev type: "
+ "%u %02x:%02x:%02x %u %u\n",
+ neighb->info->name,
+ neighb->info->model_name,
+ neighb->info->manufacturer,
+ neighb->info->model_nr,
+ neighb->info->serial,
+ neighb->info->prim_dev_type.category,
+ neighb->info->prim_dev_type.OUI[0],
+ neighb->info->prim_dev_type.OUI[1],
+ neighb->info->prim_dev_type.OUI[2],
+ neighb->info->prim_dev_type.OUIsubdiv,
+ neighb->info->prim_dev_type.subID);
+ list_for_each_entry(wssid_e, &neighb->wssid, node) {
+ used += wlp_wss_wssid_e_print(buf + used,
+ bufsize - used,
+ wssid_e);
+ }
+ buf[used++] = '\n';
+ wlp_remove_neighbor_tmp_info(neighb);
+ }
+
+
+out:
+ mutex_unlock(&wlp->nbmutex);
+ return used;
+}
+
+
+/**
+ * Show properties of all WSS in neighborhood.
+ *
+ * Will trigger a complete discovery of WSS activated by this device and
+ * its neighbors.
+ */
+ssize_t wlp_neighborhood_show(struct wlp *wlp, char *buf)
+{
+ wlp_discover(wlp);
+ return wlp_wss_neighborhood_print_remove(wlp, buf, PAGE_SIZE);
+}
+EXPORT_SYMBOL_GPL(wlp_neighborhood_show);
+
+static
+ssize_t __wlp_wss_properties_show(struct wlp_wss *wss, char *buf,
+ size_t bufsize)
+{
+ ssize_t result;
+
+ result = wlp_wss_uuid_print(buf, bufsize, &wss->wssid);
+ result += scnprintf(buf + result, bufsize - result, " ");
+ result += uwb_mac_addr_print(buf + result, bufsize - result,
+ &wss->bcast);
+ result += scnprintf(buf + result, bufsize - result,
+ " 0x%02x %u ", wss->hash, wss->secure_status);
+ result += wlp_wss_key_print(buf + result, bufsize - result,
+ wss->master_key);
+ result += scnprintf(buf + result, bufsize - result, " 0x%02x ",
+ wss->tag);
+ result += uwb_mac_addr_print(buf + result, bufsize - result,
+ &wss->virtual_addr);
+ result += scnprintf(buf + result, bufsize - result, " %s", wss->name);
+ result += scnprintf(buf + result, bufsize - result,
+ "\n\n#WSSID\n#WSS broadcast address\n"
+ "#WSS hash\n#WSS secure status\n"
+ "#WSS master key\n#WSS local tag\n"
+ "#WSS local virtual EUI-48\n#WSS name\n");
+ return result;
+}
+
+/**
+ * Show which WSS is activated.
+ */
+ssize_t wlp_wss_activate_show(struct wlp_wss *wss, char *buf)
+{
+ int result = 0;
+
+ if (mutex_lock_interruptible(&wss->mutex))
+ goto out;
+ if (wss->state >= WLP_WSS_STATE_ACTIVE)
+ result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
+ else
+ result = scnprintf(buf, PAGE_SIZE, "No local WSS active.\n");
+ result += scnprintf(buf + result, PAGE_SIZE - result,
+ "\n\n"
+ "# echo WSSID SECURE_STATUS ACCEPT_ENROLLMENT "
+ "NAME #create new WSS\n"
+ "# echo WSSID [DEV ADDR] #enroll in and activate "
+ "existing WSS, can request registrar\n"
+ "#\n"
+ "# WSSID is a 16 byte hex array. Eg. 12 A3 3B ... \n"
+ "# SECURE_STATUS 0 - unsecure, 1 - secure (default)\n"
+ "# ACCEPT_ENROLLMENT 0 - no, 1 - yes (default)\n"
+ "# NAME is the text string identifying the WSS\n"
+ "# DEV ADDR is the device address of neighbor "
+ "that should be registrar. Eg. 32:AB\n");
+
+ mutex_unlock(&wss->mutex);
+out:
+ return result;
+
+}
+EXPORT_SYMBOL_GPL(wlp_wss_activate_show);
+
+/**
+ * Create/activate a new WSS or enroll/activate in neighboring WSS
+ *
+ * The user can provide the WSSID of a WSS in which it wants to enroll.
+ * Only the WSSID is necessary if the WSS have been discovered before. If
+ * the WSS has not been discovered before, or the user wants to use a
+ * particular neighbor as its registrar, then the user can also provide a
+ * device address or the neighbor that will be used as registrar.
+ *
+ * A new WSS is created when the user provides a WSSID, secure status, and
+ * WSS name.
+ */
+ssize_t wlp_wss_activate_store(struct wlp_wss *wss,
+ const char *buf, size_t size)
+{
+ ssize_t result = -EINVAL;
+ struct wlp_uuid wssid;
+ struct uwb_dev_addr dev;
+ struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
+ char name[65];
+ unsigned sec_status, accept;
+ memset(name, 0, sizeof(name));
+ result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx:%02hhx",
+ &wssid.data[0] , &wssid.data[1],
+ &wssid.data[2] , &wssid.data[3],
+ &wssid.data[4] , &wssid.data[5],
+ &wssid.data[6] , &wssid.data[7],
+ &wssid.data[8] , &wssid.data[9],
+ &wssid.data[10], &wssid.data[11],
+ &wssid.data[12], &wssid.data[13],
+ &wssid.data[14], &wssid.data[15],
+ &dev.data[1], &dev.data[0]);
+ if (result == 16 || result == 17) {
+ result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%u %u %64c",
+ &wssid.data[0] , &wssid.data[1],
+ &wssid.data[2] , &wssid.data[3],
+ &wssid.data[4] , &wssid.data[5],
+ &wssid.data[6] , &wssid.data[7],
+ &wssid.data[8] , &wssid.data[9],
+ &wssid.data[10], &wssid.data[11],
+ &wssid.data[12], &wssid.data[13],
+ &wssid.data[14], &wssid.data[15],
+ &sec_status, &accept, name);
+ if (result == 16)
+ result = wlp_wss_enroll_activate(wss, &wssid, &bcast);
+ else if (result == 19) {
+ sec_status = sec_status == 0 ? 0 : 1;
+ accept = accept == 0 ? 0 : 1;
+ /* We read name using %c, so the newline needs to be
+ * removed */
+ if (strlen(name) != sizeof(name) - 1)
+ name[strlen(name) - 1] = '\0';
+ result = wlp_wss_create_activate(wss, &wssid, name,
+ sec_status, accept);
+ } else
+ result = -EINVAL;
+ } else if (result == 18)
+ result = wlp_wss_enroll_activate(wss, &wssid, &dev);
+ else
+ result = -EINVAL;
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(wlp_wss_activate_store);
+
+/**
+ * Show the UUID of this host
+ */
+ssize_t wlp_uuid_show(struct wlp *wlp, char *buf)
+{
+ ssize_t result = 0;
+
+ mutex_lock(&wlp->mutex);
+ result = wlp_wss_uuid_print(buf, PAGE_SIZE, &wlp->uuid);
+ buf[result++] = '\n';
+ mutex_unlock(&wlp->mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_uuid_show);
+
+/**
+ * Store a new UUID for this host
+ *
+ * According to the spec this should be encoded as an octet string in the
+ * order the octets are shown in string representation in RFC 4122 (WLP
+ * 0.99 [Table 6])
+ *
+ * We do not check value provided by user.
+ */
+ssize_t wlp_uuid_store(struct wlp *wlp, const char *buf, size_t size)
+{
+ ssize_t result;
+ struct wlp_uuid uuid;
+
+ mutex_lock(&wlp->mutex);
+ result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx "
+ "%02hhx %02hhx %02hhx %02hhx ",
+ &uuid.data[0] , &uuid.data[1],
+ &uuid.data[2] , &uuid.data[3],
+ &uuid.data[4] , &uuid.data[5],
+ &uuid.data[6] , &uuid.data[7],
+ &uuid.data[8] , &uuid.data[9],
+ &uuid.data[10], &uuid.data[11],
+ &uuid.data[12], &uuid.data[13],
+ &uuid.data[14], &uuid.data[15]);
+ if (result != 16) {
+ result = -EINVAL;
+ goto error;
+ }
+ wlp->uuid = uuid;
+error:
+ mutex_unlock(&wlp->mutex);
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(wlp_uuid_store);
+
+/**
+ * Show contents of members of device information structure
+ */
+#define wlp_dev_info_show(type) \
+ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf) \
+{ \
+ ssize_t result = 0; \
+ mutex_lock(&wlp->mutex); \
+ if (wlp->dev_info == NULL) { \
+ result = __wlp_setup_device_info(wlp); \
+ if (result < 0) \
+ goto out; \
+ } \
+ result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\
+out: \
+ mutex_unlock(&wlp->mutex); \
+ return result; \
+} \
+EXPORT_SYMBOL_GPL(wlp_dev_##type##_show);
+
+wlp_dev_info_show(name)
+wlp_dev_info_show(model_name)
+wlp_dev_info_show(model_nr)
+wlp_dev_info_show(manufacturer)
+wlp_dev_info_show(serial)
+
+/**
+ * Store contents of members of device information structure
+ */
+#define wlp_dev_info_store(type, len) \
+ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\
+{ \
+ ssize_t result; \
+ char format[10]; \
+ mutex_lock(&wlp->mutex); \
+ if (wlp->dev_info == NULL) { \
+ result = __wlp_alloc_device_info(wlp); \
+ if (result < 0) \
+ goto out; \
+ } \
+ memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type)); \
+ sprintf(format, "%%%uc", len); \
+ result = sscanf(buf, format, wlp->dev_info->type); \
+out: \
+ mutex_unlock(&wlp->mutex); \
+ return result < 0 ? result : size; \
+} \
+EXPORT_SYMBOL_GPL(wlp_dev_##type##_store);
+
+wlp_dev_info_store(name, 32)
+wlp_dev_info_store(manufacturer, 64)
+wlp_dev_info_store(model_name, 32)
+wlp_dev_info_store(model_nr, 32)
+wlp_dev_info_store(serial, 32)
+
+static
+const char *__wlp_dev_category[] = {
+ [WLP_DEV_CAT_COMPUTER] = "Computer",
+ [WLP_DEV_CAT_INPUT] = "Input device",
+ [WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER] = "Printer, scanner, FAX, or "
+ "Copier",
+ [WLP_DEV_CAT_CAMERA] = "Camera",
+ [WLP_DEV_CAT_STORAGE] = "Storage Network",
+ [WLP_DEV_CAT_INFRASTRUCTURE] = "Infrastructure",
+ [WLP_DEV_CAT_DISPLAY] = "Display",
+ [WLP_DEV_CAT_MULTIM] = "Multimedia device",
+ [WLP_DEV_CAT_GAMING] = "Gaming device",
+ [WLP_DEV_CAT_TELEPHONE] = "Telephone",
+ [WLP_DEV_CAT_OTHER] = "Other",
+};
+
+static
+const char *wlp_dev_category_str(unsigned cat)
+{
+ if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
+ || cat == WLP_DEV_CAT_OTHER)
+ return __wlp_dev_category[cat];
+ return "unknown category";
+}
+
+ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf)
+{
+ ssize_t result = 0;
+ mutex_lock(&wlp->mutex);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_setup_device_info(wlp);
+ if (result < 0)
+ goto out;
+ }
+ result = scnprintf(buf, PAGE_SIZE, "%s\n",
+ wlp_dev_category_str(wlp->dev_info->prim_dev_type.category));
+out:
+ mutex_unlock(&wlp->mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show);
+
+ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf,
+ size_t size)
+{
+ ssize_t result;
+ u16 cat;
+ mutex_lock(&wlp->mutex);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_alloc_device_info(wlp);
+ if (result < 0)
+ goto out;
+ }
+ result = sscanf(buf, "%hu", &cat);
+ if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
+ || cat == WLP_DEV_CAT_OTHER)
+ wlp->dev_info->prim_dev_type.category = cat;
+ else
+ result = -EINVAL;
+out:
+ mutex_unlock(&wlp->mutex);
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store);
+
+ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf)
+{
+ ssize_t result = 0;
+ mutex_lock(&wlp->mutex);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_setup_device_info(wlp);
+ if (result < 0)
+ goto out;
+ }
+ result = scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x\n",
+ wlp->dev_info->prim_dev_type.OUI[0],
+ wlp->dev_info->prim_dev_type.OUI[1],
+ wlp->dev_info->prim_dev_type.OUI[2]);
+out:
+ mutex_unlock(&wlp->mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show);
+
+ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size)
+{
+ ssize_t result;
+ u8 OUI[3];
+ mutex_lock(&wlp->mutex);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_alloc_device_info(wlp);
+ if (result < 0)
+ goto out;
+ }
+ result = sscanf(buf, "%hhx:%hhx:%hhx",
+ &OUI[0], &OUI[1], &OUI[2]);
+ if (result != 3) {
+ result = -EINVAL;
+ goto out;
+ } else
+ memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI));
+out:
+ mutex_unlock(&wlp->mutex);
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store);
+
+
+ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf)
+{
+ ssize_t result = 0;
+ mutex_lock(&wlp->mutex);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_setup_device_info(wlp);
+ if (result < 0)
+ goto out;
+ }
+ result = scnprintf(buf, PAGE_SIZE, "%u\n",
+ wlp->dev_info->prim_dev_type.OUIsubdiv);
+out:
+ mutex_unlock(&wlp->mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show);
+
+ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf,
+ size_t size)
+{
+ ssize_t result;
+ unsigned sub;
+ u8 max_sub = ~0;
+ mutex_lock(&wlp->mutex);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_alloc_device_info(wlp);
+ if (result < 0)
+ goto out;
+ }
+ result = sscanf(buf, "%u", &sub);
+ if (sub <= max_sub)
+ wlp->dev_info->prim_dev_type.OUIsubdiv = sub;
+ else
+ result = -EINVAL;
+out:
+ mutex_unlock(&wlp->mutex);
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store);
+
+ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf)
+{
+ ssize_t result = 0;
+ mutex_lock(&wlp->mutex);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_setup_device_info(wlp);
+ if (result < 0)
+ goto out;
+ }
+ result = scnprintf(buf, PAGE_SIZE, "%u\n",
+ wlp->dev_info->prim_dev_type.subID);
+out:
+ mutex_unlock(&wlp->mutex);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show);
+
+ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf,
+ size_t size)
+{
+ ssize_t result;
+ unsigned sub;
+ __le16 max_sub = ~0;
+ mutex_lock(&wlp->mutex);
+ if (wlp->dev_info == NULL) {
+ result = __wlp_alloc_device_info(wlp);
+ if (result < 0)
+ goto out;
+ }
+ result = sscanf(buf, "%u", &sub);
+ if (sub <= max_sub)
+ wlp->dev_info->prim_dev_type.subID = sub;
+ else
+ result = -EINVAL;
+out:
+ mutex_unlock(&wlp->mutex);
+ return result < 0 ? result : size;
+}
+EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store);
+
+/**
+ * Subsystem implementation for interaction with individual WSS via sysfs
+ *
+ * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt
+ */
+
+#define kobj_to_wlp_wss(obj) container_of(obj, struct wlp_wss, kobj)
+#define attr_to_wlp_wss_attr(_attr) \
+ container_of(_attr, struct wlp_wss_attribute, attr)
+
+/**
+ * Sysfs subsystem: forward read calls
+ *
+ * Sysfs operation for forwarding read call to the show method of the
+ * attribute owner
+ */
+static
+ssize_t wlp_wss_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
+ struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
+ ssize_t ret = -EIO;
+
+ if (wss_attr->show)
+ ret = wss_attr->show(wss, buf);
+ return ret;
+}
+/**
+ * Sysfs subsystem: forward write calls
+ *
+ * Sysfs operation for forwarding write call to the store method of the
+ * attribute owner
+ */
+static
+ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
+ struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
+ ssize_t ret = -EIO;
+
+ if (wss_attr->store)
+ ret = wss_attr->store(wss, buf, count);
+ return ret;
+}
+
+static
+struct sysfs_ops wss_sysfs_ops = {
+ .show = wlp_wss_attr_show,
+ .store = wlp_wss_attr_store,
+};
+
+struct kobj_type wss_ktype = {
+ .release = wlp_wss_release,
+ .sysfs_ops = &wss_sysfs_ops,
+};
+
+
+/**
+ * Sysfs files for individual WSS
+ */
+
+/**
+ * Print static properties of this WSS
+ *
+ * The name of a WSS may not be null teminated. It's max size is 64 bytes
+ * so we copy it to a larger array just to make sure we print sane data.
+ */
+static ssize_t wlp_wss_properties_show(struct wlp_wss *wss, char *buf)
+{
+ int result = 0;
+
+ if (mutex_lock_interruptible(&wss->mutex))
+ goto out;
+ result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
+ mutex_unlock(&wss->mutex);
+out:
+ return result;
+}
+WSS_ATTR(properties, S_IRUGO, wlp_wss_properties_show, NULL);
+
+/**
+ * Print all connected members of this WSS
+ * The EDA cache contains all members of WSS neighborhood.
+ */
+static ssize_t wlp_wss_members_show(struct wlp_wss *wss, char *buf)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ return wlp_eda_show(wlp, buf);
+}
+WSS_ATTR(members, S_IRUGO, wlp_wss_members_show, NULL);
+
+static
+const char *__wlp_strstate[] = {
+ "none",
+ "partially enrolled",
+ "enrolled",
+ "active",
+ "connected",
+};
+
+static const char *wlp_wss_strstate(unsigned state)
+{
+ if (state >= ARRAY_SIZE(__wlp_strstate))
+ return "unknown state";
+ return __wlp_strstate[state];
+}
+
+/*
+ * Print current state of this WSS
+ */
+static ssize_t wlp_wss_state_show(struct wlp_wss *wss, char *buf)
+{
+ int result = 0;
+
+ if (mutex_lock_interruptible(&wss->mutex))
+ goto out;
+ result = scnprintf(buf, PAGE_SIZE, "%s\n",
+ wlp_wss_strstate(wss->state));
+ mutex_unlock(&wss->mutex);
+out:
+ return result;
+}
+WSS_ATTR(state, S_IRUGO, wlp_wss_state_show, NULL);
+
+
+static
+struct attribute *wss_attrs[] = {
+ &wss_attr_properties.attr,
+ &wss_attr_members.attr,
+ &wss_attr_state.attr,
+ NULL,
+};
+
+struct attribute_group wss_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = wss_attrs,
+};
diff --git a/drivers/uwb/wlp/txrx.c b/drivers/uwb/wlp/txrx.c
new file mode 100644
index 00000000000..c701bd1a288
--- /dev/null
+++ b/drivers/uwb/wlp/txrx.c
@@ -0,0 +1,374 @@
+/*
+ * WiMedia Logical Link Control Protocol (WLP)
+ * Message exchange infrastructure
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Reinette Chatre <reinette.chatre@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.
+ *
+ *
+ * FIXME: Docs
+ *
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/wlp.h>
+#define D_LOCAL 5
+#include <linux/uwb/debug.h>
+#include "wlp-internal.h"
+
+
+/**
+ * Direct incoming association msg to correct parsing routine
+ *
+ * We only expect D1, E1, C1, C3 messages as new. All other incoming
+ * association messages should form part of an established session that is
+ * handled elsewhere.
+ * The handling of these messages often require calling sleeping functions
+ * - this cannot be done in interrupt context. We use the kernel's
+ * workqueue to handle these messages.
+ */
+static
+void wlp_direct_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
+ struct uwb_dev_addr *src)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_frame_assoc *assoc = (void *) skb->data;
+ struct wlp_assoc_frame_ctx *frame_ctx;
+ d_fnstart(5, dev, "wlp %p, skb %p\n", wlp, skb);
+ frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_ATOMIC);
+ if (frame_ctx == NULL) {
+ dev_err(dev, "WLP: Unable to allocate memory for association "
+ "frame handling.\n");
+ kfree_skb(skb);
+ goto out;
+ }
+ frame_ctx->wlp = wlp;
+ frame_ctx->skb = skb;
+ frame_ctx->src = *src;
+ switch (assoc->type) {
+ case WLP_ASSOC_D1:
+ d_printf(5, dev, "Received a D1 frame.\n");
+ INIT_WORK(&frame_ctx->ws, wlp_handle_d1_frame);
+ schedule_work(&frame_ctx->ws);
+ break;
+ case WLP_ASSOC_E1:
+ d_printf(5, dev, "Received a E1 frame. FIXME?\n");
+ kfree_skb(skb); /* Temporary until we handle it */
+ kfree(frame_ctx); /* Temporary until we handle it */
+ break;
+ case WLP_ASSOC_C1:
+ d_printf(5, dev, "Received a C1 frame.\n");
+ INIT_WORK(&frame_ctx->ws, wlp_handle_c1_frame);
+ schedule_work(&frame_ctx->ws);
+ break;
+ case WLP_ASSOC_C3:
+ d_printf(5, dev, "Received a C3 frame.\n");
+ INIT_WORK(&frame_ctx->ws, wlp_handle_c3_frame);
+ schedule_work(&frame_ctx->ws);
+ break;
+ default:
+ dev_err(dev, "Received unexpected association frame. "
+ "Type = %d \n", assoc->type);
+ kfree_skb(skb);
+ kfree(frame_ctx);
+ break;
+ }
+out:
+ d_fnend(5, dev, "wlp %p\n", wlp);
+}
+
+/**
+ * Process incoming association frame
+ *
+ * Although it could be possible to deal with some incoming association
+ * messages without creating a new session we are keeping things simple. We
+ * do not accept new association messages if there is a session in progress
+ * and the messages do not belong to that session.
+ *
+ * If an association message arrives that causes the creation of a session
+ * (WLP_ASSOC_E1) while we are in the process of creating a session then we
+ * rely on the neighbor mutex to protect the data. That is, the new session
+ * will not be started until the previous is completed.
+ */
+static
+void wlp_receive_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
+ struct uwb_dev_addr *src)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_frame_assoc *assoc = (void *) skb->data;
+ struct wlp_session *session = wlp->session;
+ u8 version;
+ d_fnstart(5, dev, "wlp %p, skb %p\n", wlp, skb);
+
+ if (wlp_get_version(wlp, &assoc->version, &version,
+ sizeof(assoc->version)) < 0)
+ goto error;
+ if (version != WLP_VERSION) {
+ dev_err(dev, "Unsupported WLP version in association "
+ "message.\n");
+ goto error;
+ }
+ if (session != NULL) {
+ /* Function that created this session is still holding the
+ * &wlp->mutex to protect this session. */
+ if (assoc->type == session->exp_message ||
+ assoc->type == WLP_ASSOC_F0) {
+ if (!memcmp(&session->neighbor_addr, src,
+ sizeof(*src))) {
+ session->data = skb;
+ (session->cb)(wlp);
+ } else {
+ dev_err(dev, "Received expected message from "
+ "unexpected source. Expected message "
+ "%d or F0 from %02x:%02x, but received "
+ "it from %02x:%02x. Dropping.\n",
+ session->exp_message,
+ session->neighbor_addr.data[1],
+ session->neighbor_addr.data[0],
+ src->data[1], src->data[0]);
+ goto error;
+ }
+ } else {
+ dev_err(dev, "Association already in progress. "
+ "Dropping.\n");
+ goto error;
+ }
+ } else {
+ wlp_direct_assoc_frame(wlp, skb, src);
+ }
+ d_fnend(5, dev, "wlp %p\n", wlp);
+ return;
+error:
+ kfree_skb(skb);
+ d_fnend(5, dev, "wlp %p\n", wlp);
+}
+
+/**
+ * Verify incoming frame is from connected neighbor, prep to pass to WLP client
+ *
+ * Verification proceeds according to WLP 0.99 [7.3.1]. The source address
+ * is used to determine which neighbor is sending the frame and the WSS tag
+ * is used to know to which WSS the frame belongs (we only support one WSS
+ * so this test is straight forward).
+ * With the WSS found we need to ensure that we are connected before
+ * allowing the exchange of data frames.
+ */
+static
+int wlp_verify_prep_rx_frame(struct wlp *wlp, struct sk_buff *skb,
+ struct uwb_dev_addr *src)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = -EINVAL;
+ struct wlp_eda_node eda_entry;
+ struct wlp_frame_std_abbrv_hdr *hdr = (void *) skb->data;
+
+ d_fnstart(6, dev, "wlp %p, skb %p \n", wlp, skb);
+ /*verify*/
+ result = wlp_copy_eda_node(&wlp->eda, src, &eda_entry);
+ if (result < 0) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Incoming frame is from unknown "
+ "neighbor %02x:%02x.\n", src->data[1],
+ src->data[0]);
+ goto out;
+ }
+ if (hdr->tag != eda_entry.tag) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Tag of incoming frame from "
+ "%02x:%02x does not match expected tag. "
+ "Received 0x%02x, expected 0x%02x. \n",
+ src->data[1], src->data[0], hdr->tag,
+ eda_entry.tag);
+ result = -EINVAL;
+ goto out;
+ }
+ if (eda_entry.state != WLP_WSS_CONNECTED) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Incoming frame from "
+ "%02x:%02x does is not from connected WSS.\n",
+ src->data[1], src->data[0]);
+ result = -EINVAL;
+ goto out;
+ }
+ /*prep*/
+ skb_pull(skb, sizeof(*hdr));
+out:
+ d_fnend(6, dev, "wlp %p, skb %p, result = %d \n", wlp, skb, result);
+ return result;
+}
+
+/**
+ * Receive a WLP frame from device
+ *
+ * @returns: 1 if calling function should free the skb
+ * 0 if it successfully handled skb and freed it
+ * 0 if error occured, will free skb in this case
+ */
+int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb,
+ struct uwb_dev_addr *src)
+{
+ unsigned len = skb->len;
+ void *ptr = skb->data;
+ struct wlp_frame_hdr *hdr;
+ int result = 0;
+
+ d_fnstart(6, dev, "skb (%p), len (%u)\n", skb, len);
+ if (len < sizeof(*hdr)) {
+ dev_err(dev, "Not enough data to parse WLP header.\n");
+ result = -EINVAL;
+ goto out;
+ }
+ hdr = ptr;
+ d_dump(6, dev, hdr, sizeof(*hdr));
+ if (le16_to_cpu(hdr->mux_hdr) != WLP_PROTOCOL_ID) {
+ dev_err(dev, "Not a WLP frame type.\n");
+ result = -EINVAL;
+ goto out;
+ }
+ switch (hdr->type) {
+ case WLP_FRAME_STANDARD:
+ if (len < sizeof(struct wlp_frame_std_abbrv_hdr)) {
+ dev_err(dev, "Not enough data to parse Standard "
+ "WLP header.\n");
+ goto out;
+ }
+ result = wlp_verify_prep_rx_frame(wlp, skb, src);
+ if (result < 0) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Verification of frame "
+ "from neighbor %02x:%02x failed.\n",
+ src->data[1], src->data[0]);
+ goto out;
+ }
+ result = 1;
+ break;
+ case WLP_FRAME_ABBREVIATED:
+ dev_err(dev, "Abbreviated frame received. FIXME?\n");
+ kfree_skb(skb);
+ break;
+ case WLP_FRAME_CONTROL:
+ dev_err(dev, "Control frame received. FIXME?\n");
+ kfree_skb(skb);
+ break;
+ case WLP_FRAME_ASSOCIATION:
+ if (len < sizeof(struct wlp_frame_assoc)) {
+ dev_err(dev, "Not enough data to parse Association "
+ "WLP header.\n");
+ goto out;
+ }
+ d_printf(5, dev, "Association frame received.\n");
+ wlp_receive_assoc_frame(wlp, skb, src);
+ break;
+ default:
+ dev_err(dev, "Invalid frame received.\n");
+ result = -EINVAL;
+ break;
+ }
+out:
+ if (result < 0) {
+ kfree_skb(skb);
+ result = 0;
+ }
+ d_fnend(6, dev, "skb (%p)\n", skb);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_receive_frame);
+
+
+/**
+ * Verify frame from network stack, prepare for further transmission
+ *
+ * @skb: the socket buffer that needs to be prepared for transmission (it
+ * is in need of a WLP header). If this is a broadcast frame we take
+ * over the entire transmission.
+ * If it is a unicast the WSS connection should already be established
+ * and transmission will be done by the calling function.
+ * @dst: On return this will contain the device address to which the
+ * frame is destined.
+ * @returns: 0 on success no tx : WLP header sucessfully applied to skb buffer,
+ * calling function can proceed with tx
+ * 1 on success with tx : WLP will take over transmission of this
+ * frame
+ * <0 on error
+ *
+ * The network stack (WLP client) is attempting to transmit a frame. We can
+ * only transmit data if a local WSS is at least active (connection will be
+ * done here if this is a broadcast frame and neighbor also has the WSS
+ * active).
+ *
+ * The frame can be either broadcast or unicast. Broadcast in a WSS is
+ * supported via multicast, but we don't support multicast yet (until
+ * devices start to support MAB IEs). If a broadcast frame needs to be
+ * transmitted it is treated as a unicast frame to each neighbor. In this
+ * case the WLP takes over transmission of the skb and returns 1
+ * to the caller to indicate so. Also, in this case, if a neighbor has the
+ * same WSS activated but is not connected then the WSS connection will be
+ * done at this time. The neighbor's virtual address will be learned at
+ * this time.
+ *
+ * The destination address in a unicast frame is the virtual address of the
+ * neighbor. This address only becomes known when a WSS connection is
+ * established. We thus rely on a broadcast frame to trigger the setup of
+ * WSS connections to all neighbors before we are able to send unicast
+ * frames to them. This seems reasonable as IP would usually use ARP first
+ * before any unicast frames are sent.
+ *
+ * If we are already connected to the neighbor (neighbor's virtual address
+ * is known) we just prepare the WLP header and the caller will continue to
+ * send the frame.
+ *
+ * A failure in this function usually indicates something that cannot be
+ * fixed automatically. So, if this function fails (@return < 0) the calling
+ * function should not retry to send the frame as it will very likely keep
+ * failing.
+ *
+ */
+int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp,
+ struct sk_buff *skb, struct uwb_dev_addr *dst)
+{
+ int result = -EINVAL;
+ struct ethhdr *eth_hdr = (void *) skb->data;
+
+ d_fnstart(6, dev, "wlp (%p), skb (%p) \n", wlp, skb);
+ if (is_broadcast_ether_addr(eth_hdr->h_dest)) {
+ d_printf(6, dev, "WLP: handling broadcast frame. \n");
+ result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb);
+ if (result < 0) {
+ if (printk_ratelimit())
+ dev_err(dev, "Unable to handle broadcast "
+ "frame from WLP client.\n");
+ goto out;
+ }
+ dev_kfree_skb_irq(skb);
+ result = 1;
+ /* Frame will be transmitted by WLP. */
+ } else {
+ d_printf(6, dev, "WLP: handling unicast frame. \n");
+ result = wlp_eda_for_virtual(&wlp->eda, eth_hdr->h_dest, dst,
+ wlp_wss_prep_hdr, skb);
+ if (unlikely(result < 0)) {
+ if (printk_ratelimit())
+ dev_err(dev, "Unable to prepare "
+ "skb for transmission. \n");
+ goto out;
+ }
+ }
+out:
+ d_fnend(6, dev, "wlp (%p), skb (%p). result = %d \n", wlp, skb, result);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_prepare_tx_frame);
diff --git a/drivers/uwb/wlp/wlp-internal.h b/drivers/uwb/wlp/wlp-internal.h
new file mode 100644
index 00000000000..1c94fabfb1a
--- /dev/null
+++ b/drivers/uwb/wlp/wlp-internal.h
@@ -0,0 +1,228 @@
+/*
+ * WiMedia Logical Link Control Protocol (WLP)
+ * Internal API
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Reinette Chatre <reinette.chatre@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 __WLP_INTERNAL_H__
+#define __WLP_INTERNAL_H__
+
+/**
+ * State of WSS connection
+ *
+ * A device needs to connect to a neighbor in an activated WSS before data
+ * can be transmitted. The spec also distinguishes between a new connection
+ * attempt and a connection attempt after previous connection attempts. The
+ * state WLP_WSS_CONNECT_FAILED is used for this scenario. See WLP 0.99
+ * [7.2.6]
+ */
+enum wlp_wss_connect {
+ WLP_WSS_UNCONNECTED = 0,
+ WLP_WSS_CONNECTED,
+ WLP_WSS_CONNECT_FAILED,
+};
+
+extern struct kobj_type wss_ktype;
+extern struct attribute_group wss_attr_group;
+
+extern int uwb_rc_ie_add(struct uwb_rc *, const struct uwb_ie_hdr *, size_t);
+extern int uwb_rc_ie_rm(struct uwb_rc *, enum uwb_ie);
+
+
+/* This should be changed to a dynamic array where entries are sorted
+ * by eth_addr and search is done in a binary form
+ *
+ * Although thinking twice about it: this technologie's maximum reach
+ * is 10 meters...unless you want to pack too much stuff in around
+ * your radio controller/WLP device, the list will probably not be
+ * too big.
+ *
+ * In any case, there is probably some data structure in the kernel
+ * than we could reused for that already.
+ *
+ * The below structure is really just good while we support one WSS per
+ * host.
+ */
+struct wlp_eda_node {
+ struct list_head list_node;
+ unsigned char eth_addr[ETH_ALEN];
+ struct uwb_dev_addr dev_addr;
+ struct wlp_wss *wss;
+ unsigned char virt_addr[ETH_ALEN];
+ u8 tag;
+ enum wlp_wss_connect state;
+};
+
+typedef int (*wlp_eda_for_each_f)(struct wlp *, struct wlp_eda_node *, void *);
+
+extern void wlp_eda_init(struct wlp_eda *);
+extern void wlp_eda_release(struct wlp_eda *);
+extern int wlp_eda_create_node(struct wlp_eda *,
+ const unsigned char eth_addr[ETH_ALEN],
+ const struct uwb_dev_addr *);
+extern void wlp_eda_rm_node(struct wlp_eda *, const struct uwb_dev_addr *);
+extern int wlp_eda_update_node(struct wlp_eda *,
+ const struct uwb_dev_addr *,
+ struct wlp_wss *,
+ const unsigned char virt_addr[ETH_ALEN],
+ const u8, const enum wlp_wss_connect);
+extern int wlp_eda_update_node_state(struct wlp_eda *,
+ const struct uwb_dev_addr *,
+ const enum wlp_wss_connect);
+
+extern int wlp_copy_eda_node(struct wlp_eda *, struct uwb_dev_addr *,
+ struct wlp_eda_node *);
+extern int wlp_eda_for_each(struct wlp_eda *, wlp_eda_for_each_f , void *);
+extern int wlp_eda_for_virtual(struct wlp_eda *,
+ const unsigned char eth_addr[ETH_ALEN],
+ struct uwb_dev_addr *,
+ wlp_eda_for_each_f , void *);
+
+
+extern void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *);
+
+extern size_t wlp_wss_key_print(char *, size_t, u8 *);
+
+/* Function called when no more references to WSS exists */
+extern void wlp_wss_release(struct kobject *);
+
+extern void wlp_wss_reset(struct wlp_wss *);
+extern int wlp_wss_create_activate(struct wlp_wss *, struct wlp_uuid *,
+ char *, unsigned, unsigned);
+extern int wlp_wss_enroll_activate(struct wlp_wss *, struct wlp_uuid *,
+ struct uwb_dev_addr *);
+extern ssize_t wlp_discover(struct wlp *);
+
+extern int wlp_enroll_neighbor(struct wlp *, struct wlp_neighbor_e *,
+ struct wlp_wss *, struct wlp_uuid *);
+extern int wlp_wss_is_active(struct wlp *, struct wlp_wss *,
+ struct uwb_dev_addr *);
+
+struct wlp_assoc_conn_ctx {
+ struct work_struct ws;
+ struct wlp *wlp;
+ struct sk_buff *skb;
+ struct wlp_eda_node eda_entry;
+};
+
+
+extern int wlp_wss_connect_prep(struct wlp *, struct wlp_eda_node *, void *);
+extern int wlp_wss_send_copy(struct wlp *, struct wlp_eda_node *, void *);
+
+
+/* Message handling */
+struct wlp_assoc_frame_ctx {
+ struct work_struct ws;
+ struct wlp *wlp;
+ struct sk_buff *skb;
+ struct uwb_dev_addr src;
+};
+
+extern int wlp_wss_prep_hdr(struct wlp *, struct wlp_eda_node *, void *);
+extern void wlp_handle_d1_frame(struct work_struct *);
+extern int wlp_parse_d2_frame_to_cache(struct wlp *, struct sk_buff *,
+ struct wlp_neighbor_e *);
+extern int wlp_parse_d2_frame_to_enroll(struct wlp_wss *, struct sk_buff *,
+ struct wlp_neighbor_e *,
+ struct wlp_uuid *);
+extern void wlp_handle_c1_frame(struct work_struct *);
+extern void wlp_handle_c3_frame(struct work_struct *);
+extern int wlp_parse_c3c4_frame(struct wlp *, struct sk_buff *,
+ struct wlp_uuid *, u8 *,
+ struct uwb_mac_addr *);
+extern int wlp_parse_f0(struct wlp *, struct sk_buff *);
+extern int wlp_send_assoc_frame(struct wlp *, struct wlp_wss *,
+ struct uwb_dev_addr *, enum wlp_assoc_type);
+extern ssize_t wlp_get_version(struct wlp *, struct wlp_attr_version *,
+ u8 *, ssize_t);
+extern ssize_t wlp_get_wssid(struct wlp *, struct wlp_attr_wssid *,
+ struct wlp_uuid *, ssize_t);
+extern int __wlp_alloc_device_info(struct wlp *);
+extern int __wlp_setup_device_info(struct wlp *);
+
+extern struct wlp_wss_attribute wss_attribute_properties;
+extern struct wlp_wss_attribute wss_attribute_members;
+extern struct wlp_wss_attribute wss_attribute_state;
+
+static inline
+size_t wlp_wss_uuid_print(char *buf, size_t bufsize, struct wlp_uuid *uuid)
+{
+ size_t result;
+
+ result = scnprintf(buf, bufsize,
+ "%02x:%02x:%02x:%02x:%02x:%02x:"
+ "%02x:%02x:%02x:%02x:%02x:%02x:"
+ "%02x:%02x:%02x:%02x",
+ uuid->data[0], uuid->data[1],
+ uuid->data[2], uuid->data[3],
+ uuid->data[4], uuid->data[5],
+ uuid->data[6], uuid->data[7],
+ uuid->data[8], uuid->data[9],
+ uuid->data[10], uuid->data[11],
+ uuid->data[12], uuid->data[13],
+ uuid->data[14], uuid->data[15]);
+ return result;
+}
+
+/**
+ * FIXME: How should a nonce be displayed?
+ */
+static inline
+size_t wlp_wss_nonce_print(char *buf, size_t bufsize, struct wlp_nonce *nonce)
+{
+ size_t result;
+
+ result = scnprintf(buf, bufsize,
+ "%02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x",
+ nonce->data[0], nonce->data[1],
+ nonce->data[2], nonce->data[3],
+ nonce->data[4], nonce->data[5],
+ nonce->data[6], nonce->data[7],
+ nonce->data[8], nonce->data[9],
+ nonce->data[10], nonce->data[11],
+ nonce->data[12], nonce->data[13],
+ nonce->data[14], nonce->data[15]);
+ return result;
+}
+
+
+static inline
+void wlp_session_cb(struct wlp *wlp)
+{
+ struct completion *completion = wlp->session->cb_priv;
+ complete(completion);
+}
+
+static inline
+int wlp_uuid_is_set(struct wlp_uuid *uuid)
+{
+ struct wlp_uuid zero_uuid = { .data = { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00} };
+
+ if (!memcmp(uuid, &zero_uuid, sizeof(*uuid)))
+ return 0;
+ return 1;
+}
+
+#endif /* __WLP_INTERNAL_H__ */
diff --git a/drivers/uwb/wlp/wlp-lc.c b/drivers/uwb/wlp/wlp-lc.c
new file mode 100644
index 00000000000..0799402e73f
--- /dev/null
+++ b/drivers/uwb/wlp/wlp-lc.c
@@ -0,0 +1,585 @@
+/*
+ * WiMedia Logical Link Control Protocol (WLP)
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Reinette Chatre <reinette.chatre@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.
+ *
+ *
+ * FIXME: docs
+ */
+
+#include <linux/wlp.h>
+#define D_LOCAL 6
+#include <linux/uwb/debug.h>
+#include "wlp-internal.h"
+
+
+static
+void wlp_neighbor_init(struct wlp_neighbor_e *neighbor)
+{
+ INIT_LIST_HEAD(&neighbor->wssid);
+}
+
+/**
+ * Create area for device information storage
+ *
+ * wlp->mutex must be held
+ */
+int __wlp_alloc_device_info(struct wlp *wlp)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ BUG_ON(wlp->dev_info != NULL);
+ wlp->dev_info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
+ if (wlp->dev_info == NULL) {
+ dev_err(dev, "WLP: Unable to allocate memory for "
+ "device information.\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+
+/**
+ * Fill in device information using function provided by driver
+ *
+ * wlp->mutex must be held
+ */
+static
+void __wlp_fill_device_info(struct wlp *wlp)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+
+ BUG_ON(wlp->fill_device_info == NULL);
+ d_printf(6, dev, "Retrieving device information "
+ "from device driver.\n");
+ wlp->fill_device_info(wlp, wlp->dev_info);
+}
+
+/**
+ * Setup device information
+ *
+ * Allocate area for device information and populate it.
+ *
+ * wlp->mutex must be held
+ */
+int __wlp_setup_device_info(struct wlp *wlp)
+{
+ int result;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+
+ result = __wlp_alloc_device_info(wlp);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to allocate area for "
+ "device information.\n");
+ return result;
+ }
+ __wlp_fill_device_info(wlp);
+ return 0;
+}
+
+/**
+ * Remove information about neighbor stored temporarily
+ *
+ * Information learned during discovey should only be stored when the
+ * device enrolls in the neighbor's WSS. We do need to store this
+ * information temporarily in order to present it to the user.
+ *
+ * We are only interested in keeping neighbor WSS information if that
+ * neighbor is accepting enrollment.
+ *
+ * should be called with wlp->nbmutex held
+ */
+void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *neighbor)
+{
+ struct wlp_wssid_e *wssid_e, *next;
+ u8 keep;
+ if (!list_empty(&neighbor->wssid)) {
+ list_for_each_entry_safe(wssid_e, next, &neighbor->wssid,
+ node) {
+ if (wssid_e->info != NULL) {
+ keep = wssid_e->info->accept_enroll;
+ kfree(wssid_e->info);
+ wssid_e->info = NULL;
+ if (!keep) {
+ list_del(&wssid_e->node);
+ kfree(wssid_e);
+ }
+ }
+ }
+ }
+ if (neighbor->info != NULL) {
+ kfree(neighbor->info);
+ neighbor->info = NULL;
+ }
+}
+
+/**
+ * Populate WLP neighborhood cache with neighbor information
+ *
+ * A new neighbor is found. If it is discoverable then we add it to the
+ * neighborhood cache.
+ *
+ */
+static
+int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev)
+{
+ int result = 0;
+ int discoverable;
+ struct wlp_neighbor_e *neighbor;
+
+ d_fnstart(6, &dev->dev, "uwb %p \n", dev);
+ d_printf(6, &dev->dev, "Found neighbor device %02x:%02x \n",
+ dev->dev_addr.data[1], dev->dev_addr.data[0]);
+ /**
+ * FIXME:
+ * Use contents of WLP IE found in beacon cache to determine if
+ * neighbor is discoverable.
+ * The device does not support WLP IE yet so this still needs to be
+ * done. Until then we assume all devices are discoverable.
+ */
+ discoverable = 1; /* will be changed when FIXME disappears */
+ if (discoverable) {
+ /* Add neighbor to cache for discovery */
+ neighbor = kzalloc(sizeof(*neighbor), GFP_KERNEL);
+ if (neighbor == NULL) {
+ dev_err(&dev->dev, "Unable to create memory for "
+ "new neighbor. \n");
+ result = -ENOMEM;
+ goto error_no_mem;
+ }
+ wlp_neighbor_init(neighbor);
+ uwb_dev_get(dev);
+ neighbor->uwb_dev = dev;
+ list_add(&neighbor->node, &wlp->neighbors);
+ }
+error_no_mem:
+ d_fnend(6, &dev->dev, "uwb %p, result = %d \n", dev, result);
+ return result;
+}
+
+/**
+ * Remove one neighbor from cache
+ */
+static
+void __wlp_neighbor_release(struct wlp_neighbor_e *neighbor)
+{
+ struct wlp_wssid_e *wssid_e, *next_wssid_e;
+
+ list_for_each_entry_safe(wssid_e, next_wssid_e,
+ &neighbor->wssid, node) {
+ list_del(&wssid_e->node);
+ kfree(wssid_e);
+ }
+ uwb_dev_put(neighbor->uwb_dev);
+ list_del(&neighbor->node);
+ kfree(neighbor);
+}
+
+/**
+ * Clear entire neighborhood cache.
+ */
+static
+void __wlp_neighbors_release(struct wlp *wlp)
+{
+ struct wlp_neighbor_e *neighbor, *next;
+ if (list_empty(&wlp->neighbors))
+ return;
+ list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
+ __wlp_neighbor_release(neighbor);
+ }
+}
+
+static
+void wlp_neighbors_release(struct wlp *wlp)
+{
+ mutex_lock(&wlp->nbmutex);
+ __wlp_neighbors_release(wlp);
+ mutex_unlock(&wlp->nbmutex);
+}
+
+
+
+/**
+ * Send D1 message to neighbor, receive D2 message
+ *
+ * @neighbor: neighbor to which D1 message will be sent
+ * @wss: if not NULL, it is an enrollment request for this WSS
+ * @wssid: if wss not NULL, this is the wssid of the WSS in which we
+ * want to enroll
+ *
+ * A D1/D2 exchange is done for one of two reasons: discovery or
+ * enrollment. If done for discovery the D1 message is sent to the neighbor
+ * and the contents of the D2 response is stored in a temporary cache.
+ * If done for enrollment the @wss and @wssid are provided also. In this
+ * case the D1 message is sent to the neighbor, the D2 response is parsed
+ * for enrollment of the WSS with wssid.
+ *
+ * &wss->mutex is held
+ */
+static
+int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
+ struct wlp_wss *wss, struct wlp_uuid *wssid)
+{
+ int result;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ DECLARE_COMPLETION_ONSTACK(completion);
+ struct wlp_session session;
+ struct sk_buff *skb;
+ struct wlp_frame_assoc *resp;
+ struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
+
+ mutex_lock(&wlp->mutex);
+ if (!wlp_uuid_is_set(&wlp->uuid)) {
+ dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
+ "proceed.\n");
+ result = -ENXIO;
+ goto out;
+ }
+ /* Send D1 association frame */
+ result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_D1);
+ if (result < 0) {
+ dev_err(dev, "Unable to send D1 frame to neighbor "
+ "%02x:%02x (%d)\n", dev_addr->data[1],
+ dev_addr->data[0], result);
+ d_printf(6, dev, "Add placeholders into buffer next to "
+ "neighbor information we have (dev address).\n");
+ goto out;
+ }
+ /* Create session, wait for response */
+ session.exp_message = WLP_ASSOC_D2;
+ session.cb = wlp_session_cb;
+ session.cb_priv = &completion;
+ session.neighbor_addr = *dev_addr;
+ BUG_ON(wlp->session != NULL);
+ wlp->session = &session;
+ /* Wait for D2/F0 frame */
+ result = wait_for_completion_interruptible_timeout(&completion,
+ WLP_PER_MSG_TIMEOUT * HZ);
+ if (result == 0) {
+ result = -ETIMEDOUT;
+ dev_err(dev, "Timeout while sending D1 to neighbor "
+ "%02x:%02x.\n", dev_addr->data[1],
+ dev_addr->data[0]);
+ goto error_session;
+ }
+ if (result < 0) {
+ dev_err(dev, "Unable to discover/enroll neighbor %02x:%02x.\n",
+ dev_addr->data[1], dev_addr->data[0]);
+ goto error_session;
+ }
+ /* Parse message in session->data: it will be either D2 or F0 */
+ skb = session.data;
+ resp = (void *) skb->data;
+ d_printf(6, dev, "Received response to D1 frame. \n");
+ d_dump(6, dev, skb->data, skb->len > 72 ? 72 : skb->len);
+
+ if (resp->type == WLP_ASSOC_F0) {
+ result = wlp_parse_f0(wlp, skb);
+ if (result < 0)
+ dev_err(dev, "WLP: Unable to parse F0 from neighbor "
+ "%02x:%02x.\n", dev_addr->data[1],
+ dev_addr->data[0]);
+ result = -EINVAL;
+ goto error_resp_parse;
+ }
+ if (wss == NULL) {
+ /* Discovery */
+ result = wlp_parse_d2_frame_to_cache(wlp, skb, neighbor);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to parse D2 message from "
+ "neighbor %02x:%02x for discovery.\n",
+ dev_addr->data[1], dev_addr->data[0]);
+ goto error_resp_parse;
+ }
+ } else {
+ /* Enrollment */
+ result = wlp_parse_d2_frame_to_enroll(wss, skb, neighbor,
+ wssid);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to parse D2 message from "
+ "neighbor %02x:%02x for enrollment.\n",
+ dev_addr->data[1], dev_addr->data[0]);
+ goto error_resp_parse;
+ }
+ }
+error_resp_parse:
+ kfree_skb(skb);
+error_session:
+ wlp->session = NULL;
+out:
+ mutex_unlock(&wlp->mutex);
+ return result;
+}
+
+/**
+ * Enroll into WSS of provided WSSID by using neighbor as registrar
+ *
+ * &wss->mutex is held
+ */
+int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
+ struct wlp_wss *wss, struct wlp_uuid *wssid)
+{
+ int result = 0;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
+ wlp_wss_uuid_print(buf, sizeof(buf), wssid);
+ d_fnstart(6, dev, "wlp %p, neighbor %p, wss %p, wssid %p (%s)\n",
+ wlp, neighbor, wss, wssid, buf);
+ d_printf(6, dev, "Complete me.\n");
+ result = wlp_d1d2_exchange(wlp, neighbor, wss, wssid);
+ if (result < 0) {
+ dev_err(dev, "WLP: D1/D2 message exchange for enrollment "
+ "failed. result = %d \n", result);
+ goto out;
+ }
+ if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
+ dev_err(dev, "WLP: Unable to enroll into WSS %s using "
+ "neighbor %02x:%02x. \n", buf,
+ dev_addr->data[1], dev_addr->data[0]);
+ result = -EINVAL;
+ goto out;
+ }
+ if (wss->secure_status == WLP_WSS_SECURE) {
+ dev_err(dev, "FIXME: need to complete secure enrollment.\n");
+ result = -EINVAL;
+ goto error;
+ } else {
+ wss->state = WLP_WSS_STATE_ENROLLED;
+ d_printf(2, dev, "WLP: Success Enrollment into unsecure WSS "
+ "%s using neighbor %02x:%02x. \n", buf,
+ dev_addr->data[1], dev_addr->data[0]);
+ }
+
+ d_fnend(6, dev, "wlp %p, neighbor %p, wss %p, wssid %p (%s)\n",
+ wlp, neighbor, wss, wssid, buf);
+out:
+ return result;
+error:
+ wlp_wss_reset(wss);
+ return result;
+}
+
+/**
+ * Discover WSS information of neighbor's active WSS
+ */
+static
+int wlp_discover_neighbor(struct wlp *wlp,
+ struct wlp_neighbor_e *neighbor)
+{
+ return wlp_d1d2_exchange(wlp, neighbor, NULL, NULL);
+}
+
+
+/**
+ * Each neighbor in the neighborhood cache is discoverable. Discover it.
+ *
+ * Discovery is done through sending of D1 association frame and parsing
+ * the D2 association frame response. Only wssid from D2 will be included
+ * in neighbor cache, rest is just displayed to user and forgotten.
+ *
+ * The discovery is not done in parallel. This is simple and enables us to
+ * maintain only one association context.
+ *
+ * The discovery of one neighbor does not affect the other, but if the
+ * discovery of a neighbor fails it is removed from the neighborhood cache.
+ */
+static
+int wlp_discover_all_neighbors(struct wlp *wlp)
+{
+ int result = 0;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_neighbor_e *neighbor, *next;
+
+ list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
+ result = wlp_discover_neighbor(wlp, neighbor);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to discover neighbor "
+ "%02x:%02x, removing from neighborhood. \n",
+ neighbor->uwb_dev->dev_addr.data[1],
+ neighbor->uwb_dev->dev_addr.data[0]);
+ __wlp_neighbor_release(neighbor);
+ }
+ }
+ return result;
+}
+
+static int wlp_add_neighbor_helper(struct device *dev, void *priv)
+{
+ struct wlp *wlp = priv;
+ struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+ return wlp_add_neighbor(wlp, uwb_dev);
+}
+
+/**
+ * Discover WLP neighborhood
+ *
+ * Will send D1 association frame to all devices in beacon group that have
+ * discoverable bit set in WLP IE. D2 frames will be received, information
+ * displayed to user in @buf. Partial information (from D2 association
+ * frame) will be cached to assist with future association
+ * requests.
+ *
+ * The discovery of the WLP neighborhood is triggered by the user. This
+ * should occur infrequently and we thus free current cache and re-allocate
+ * memory if needed.
+ *
+ * If one neighbor fails during initial discovery (determining if it is a
+ * neighbor or not), we fail all - note that interaction with neighbor has
+ * not occured at this point so if a failure occurs we know something went wrong
+ * locally. We thus undo everything.
+ */
+ssize_t wlp_discover(struct wlp *wlp)
+{
+ int result = 0;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+
+ d_fnstart(6, dev, "wlp %p \n", wlp);
+ mutex_lock(&wlp->nbmutex);
+ /* Clear current neighborhood cache. */
+ __wlp_neighbors_release(wlp);
+ /* Determine which devices in neighborhood. Repopulate cache. */
+ result = uwb_dev_for_each(wlp->rc, wlp_add_neighbor_helper, wlp);
+ if (result < 0) {
+ /* May have partial neighbor information, release all. */
+ __wlp_neighbors_release(wlp);
+ goto error_dev_for_each;
+ }
+ /* Discover the properties of devices in neighborhood. */
+ result = wlp_discover_all_neighbors(wlp);
+ /* In case of failure we still print our partial results. */
+ if (result < 0) {
+ dev_err(dev, "Unable to fully discover neighborhood. \n");
+ result = 0;
+ }
+error_dev_for_each:
+ mutex_unlock(&wlp->nbmutex);
+ d_fnend(6, dev, "wlp %p \n", wlp);
+ return result;
+}
+
+/**
+ * Handle events from UWB stack
+ *
+ * We handle events conservatively. If a neighbor goes off the air we
+ * remove it from the neighborhood. If an association process is in
+ * progress this function will block waiting for the nbmutex to become
+ * free. The association process will thus be allowed to complete before it
+ * is removed.
+ */
+static
+void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev,
+ enum uwb_notifs event)
+{
+ struct wlp *wlp = _wlp;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_neighbor_e *neighbor, *next;
+ int result;
+ switch (event) {
+ case UWB_NOTIF_ONAIR:
+ d_printf(6, dev, "UWB device %02x:%02x is onair\n",
+ uwb_dev->dev_addr.data[1],
+ uwb_dev->dev_addr.data[0]);
+ result = wlp_eda_create_node(&wlp->eda,
+ uwb_dev->mac_addr.data,
+ &uwb_dev->dev_addr);
+ if (result < 0)
+ dev_err(dev, "WLP: Unable to add new neighbor "
+ "%02x:%02x to EDA cache.\n",
+ uwb_dev->dev_addr.data[1],
+ uwb_dev->dev_addr.data[0]);
+ break;
+ case UWB_NOTIF_OFFAIR:
+ d_printf(6, dev, "UWB device %02x:%02x is offair\n",
+ uwb_dev->dev_addr.data[1],
+ uwb_dev->dev_addr.data[0]);
+ wlp_eda_rm_node(&wlp->eda, &uwb_dev->dev_addr);
+ mutex_lock(&wlp->nbmutex);
+ list_for_each_entry_safe(neighbor, next, &wlp->neighbors,
+ node) {
+ if (neighbor->uwb_dev == uwb_dev) {
+ d_printf(6, dev, "Removing device from "
+ "neighborhood.\n");
+ __wlp_neighbor_release(neighbor);
+ }
+ }
+ mutex_unlock(&wlp->nbmutex);
+ break;
+ default:
+ dev_err(dev, "don't know how to handle event %d from uwb\n",
+ event);
+ }
+}
+
+int wlp_setup(struct wlp *wlp, struct uwb_rc *rc)
+{
+ struct device *dev = &rc->uwb_dev.dev;
+ int result;
+
+ d_fnstart(6, dev, "wlp %p\n", wlp);
+ BUG_ON(wlp->fill_device_info == NULL);
+ BUG_ON(wlp->xmit_frame == NULL);
+ BUG_ON(wlp->stop_queue == NULL);
+ BUG_ON(wlp->start_queue == NULL);
+ wlp->rc = rc;
+ wlp_eda_init(&wlp->eda);/* Set up address cache */
+ wlp->uwb_notifs_handler.cb = wlp_uwb_notifs_cb;
+ wlp->uwb_notifs_handler.data = wlp;
+ uwb_notifs_register(rc, &wlp->uwb_notifs_handler);
+
+ uwb_pal_init(&wlp->pal);
+ result = uwb_pal_register(rc, &wlp->pal);
+ if (result < 0)
+ uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
+
+ d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_setup);
+
+void wlp_remove(struct wlp *wlp)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ d_fnstart(6, dev, "wlp %p\n", wlp);
+ wlp_neighbors_release(wlp);
+ uwb_pal_unregister(wlp->rc, &wlp->pal);
+ uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
+ wlp_eda_release(&wlp->eda);
+ mutex_lock(&wlp->mutex);
+ if (wlp->dev_info != NULL)
+ kfree(wlp->dev_info);
+ mutex_unlock(&wlp->mutex);
+ wlp->rc = NULL;
+ /* We have to use NULL here because this function can be called
+ * when the device disappeared. */
+ d_fnend(6, NULL, "wlp %p\n", wlp);
+}
+EXPORT_SYMBOL_GPL(wlp_remove);
+
+/**
+ * wlp_reset_all - reset the WLP hardware
+ * @wlp: the WLP device to reset.
+ *
+ * This schedules a full hardware reset of the WLP device. The radio
+ * controller and any other PALs will also be reset.
+ */
+void wlp_reset_all(struct wlp *wlp)
+{
+ uwb_rc_reset_all(wlp->rc);
+}
+EXPORT_SYMBOL_GPL(wlp_reset_all);
diff --git a/drivers/uwb/wlp/wss-lc.c b/drivers/uwb/wlp/wss-lc.c
new file mode 100644
index 00000000000..96b18c9bd6e
--- /dev/null
+++ b/drivers/uwb/wlp/wss-lc.c
@@ -0,0 +1,1055 @@
+/*
+ * WiMedia Logical Link Control Protocol (WLP)
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Reinette Chatre <reinette.chatre@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.
+ *
+ *
+ * Implementation of the WLP association protocol.
+ *
+ * FIXME: Docs
+ *
+ * A UWB network interface will configure a WSS through wlp_wss_setup() after
+ * the interface has been assigned a MAC address, typically after
+ * "ifconfig" has been called. When the interface goes down it should call
+ * wlp_wss_remove().
+ *
+ * When the WSS is ready for use the user interacts via sysfs to create,
+ * discover, and activate WSS.
+ *
+ * wlp_wss_enroll_activate()
+ *
+ * wlp_wss_create_activate()
+ * wlp_wss_set_wssid_hash()
+ * wlp_wss_comp_wssid_hash()
+ * wlp_wss_sel_bcast_addr()
+ * wlp_wss_sysfs_add()
+ *
+ * Called when no more references to WSS exist:
+ * wlp_wss_release()
+ * wlp_wss_reset()
+ */
+
+#include <linux/etherdevice.h> /* for is_valid_ether_addr */
+#include <linux/skbuff.h>
+#include <linux/wlp.h>
+#define D_LOCAL 5
+#include <linux/uwb/debug.h>
+#include "wlp-internal.h"
+
+
+size_t wlp_wss_key_print(char *buf, size_t bufsize, u8 *key)
+{
+ size_t result;
+
+ result = scnprintf(buf, bufsize,
+ "%02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x",
+ key[0], key[1], key[2], key[3],
+ key[4], key[5], key[6], key[7],
+ key[8], key[9], key[10], key[11],
+ key[12], key[13], key[14], key[15]);
+ return result;
+}
+
+/**
+ * Compute WSSID hash
+ * WLP Draft 0.99 [7.2.1]
+ *
+ * The WSSID hash for a WSSID is the result of an octet-wise exclusive-OR
+ * of all octets in the WSSID.
+ */
+static
+u8 wlp_wss_comp_wssid_hash(struct wlp_uuid *wssid)
+{
+ return wssid->data[0] ^ wssid->data[1] ^ wssid->data[2]
+ ^ wssid->data[3] ^ wssid->data[4] ^ wssid->data[5]
+ ^ wssid->data[6] ^ wssid->data[7] ^ wssid->data[8]
+ ^ wssid->data[9] ^ wssid->data[10] ^ wssid->data[11]
+ ^ wssid->data[12] ^ wssid->data[13] ^ wssid->data[14]
+ ^ wssid->data[15];
+}
+
+/**
+ * Select a multicast EUI-48 for the WSS broadcast address.
+ * WLP Draft 0.99 [7.2.1]
+ *
+ * Selected based on the WiMedia Alliance OUI, 00-13-88, within the WLP
+ * range, [01-13-88-00-01-00, 01-13-88-00-01-FF] inclusive.
+ *
+ * This address is currently hardcoded.
+ * FIXME?
+ */
+static
+struct uwb_mac_addr wlp_wss_sel_bcast_addr(struct wlp_wss *wss)
+{
+ struct uwb_mac_addr bcast = {
+ .data = { 0x01, 0x13, 0x88, 0x00, 0x01, 0x00 }
+ };
+ return bcast;
+}
+
+/**
+ * Clear the contents of the WSS structure - all except kobj, mutex, virtual
+ *
+ * We do not want to reinitialize - the internal kobj should not change as
+ * it still points to the parent received during setup. The mutex should
+ * remain also. We thus just reset values individually.
+ * The virutal address assigned to WSS will remain the same for the
+ * lifetime of the WSS. We only reset the fields that can change during its
+ * lifetime.
+ */
+void wlp_wss_reset(struct wlp_wss *wss)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ d_fnstart(5, dev, "wss (%p) \n", wss);
+ memset(&wss->wssid, 0, sizeof(wss->wssid));
+ wss->hash = 0;
+ memset(&wss->name[0], 0, sizeof(wss->name));
+ memset(&wss->bcast, 0, sizeof(wss->bcast));
+ wss->secure_status = WLP_WSS_UNSECURE;
+ memset(&wss->master_key[0], 0, sizeof(wss->master_key));
+ wss->tag = 0;
+ wss->state = WLP_WSS_STATE_NONE;
+ d_fnend(5, dev, "wss (%p) \n", wss);
+}
+
+/**
+ * Create sysfs infrastructure for WSS
+ *
+ * The WSS is configured to have the interface as parent (see wlp_wss_setup())
+ * a new sysfs directory that includes wssid as its name is created in the
+ * interface's sysfs directory. The group of files interacting with WSS are
+ * created also.
+ */
+static
+int wlp_wss_sysfs_add(struct wlp_wss *wss, char *wssid_str)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result;
+
+ d_fnstart(5, dev, "wss (%p), wssid: %s\n", wss, wssid_str);
+ result = kobject_set_name(&wss->kobj, "wss-%s", wssid_str);
+ if (result < 0)
+ return result;
+ wss->kobj.ktype = &wss_ktype;
+ result = kobject_init_and_add(&wss->kobj,
+ &wss_ktype, wss->kobj.parent, "wlp");
+ if (result < 0) {
+ dev_err(dev, "WLP: Cannot register WSS kobject.\n");
+ goto error_kobject_register;
+ }
+ result = sysfs_create_group(&wss->kobj, &wss_attr_group);
+ if (result < 0) {
+ dev_err(dev, "WLP: Cannot register WSS attributes: %d\n",
+ result);
+ goto error_sysfs_create_group;
+ }
+ d_fnend(5, dev, "Completed. result = %d \n", result);
+ return 0;
+error_sysfs_create_group:
+
+ kobject_put(&wss->kobj); /* will free name if needed */
+ return result;
+error_kobject_register:
+ kfree(wss->kobj.name);
+ wss->kobj.name = NULL;
+ wss->kobj.ktype = NULL;
+ return result;
+}
+
+
+/**
+ * Release WSS
+ *
+ * No more references exist to this WSS. We should undo everything that was
+ * done in wlp_wss_create_activate() except removing the group. The group
+ * is not removed because an object can be unregistered before the group is
+ * created. We also undo any additional operations on the WSS after this
+ * (addition of members).
+ *
+ * If memory was allocated for the kobject's name then it will
+ * be freed by the kobject system during this time.
+ *
+ * The EDA cache is removed and reinitilized when the WSS is removed. We
+ * thus loose knowledge of members of this WSS at that time and need not do
+ * it here.
+ */
+void wlp_wss_release(struct kobject *kobj)
+{
+ struct wlp_wss *wss = container_of(kobj, struct wlp_wss, kobj);
+
+ wlp_wss_reset(wss);
+}
+
+/**
+ * Enroll into a WSS using provided neighbor as registrar
+ *
+ * First search the neighborhood information to learn which neighbor is
+ * referred to, next proceed with enrollment.
+ *
+ * &wss->mutex is held
+ */
+static
+int wlp_wss_enroll_target(struct wlp_wss *wss, struct wlp_uuid *wssid,
+ struct uwb_dev_addr *dest)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_neighbor_e *neighbor;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ int result = -ENXIO;
+ struct uwb_dev_addr *dev_addr;
+
+ wlp_wss_uuid_print(buf, sizeof(buf), wssid);
+ d_fnstart(5, dev, "wss %p, wssid %s, registrar %02x:%02x \n",
+ wss, buf, dest->data[1], dest->data[0]);
+ mutex_lock(&wlp->nbmutex);
+ list_for_each_entry(neighbor, &wlp->neighbors, node) {
+ dev_addr = &neighbor->uwb_dev->dev_addr;
+ if (!memcmp(dest, dev_addr, sizeof(*dest))) {
+ d_printf(5, dev, "Neighbor %02x:%02x is valid, "
+ "enrolling. \n",
+ dev_addr->data[1], dev_addr->data[0]);
+ result = wlp_enroll_neighbor(wlp, neighbor, wss,
+ wssid);
+ break;
+ }
+ }
+ if (result == -ENXIO)
+ dev_err(dev, "WLP: Cannot find neighbor %02x:%02x. \n",
+ dest->data[1], dest->data[0]);
+ mutex_unlock(&wlp->nbmutex);
+ d_fnend(5, dev, "wss %p, wssid %s, registrar %02x:%02x, result %d \n",
+ wss, buf, dest->data[1], dest->data[0], result);
+ return result;
+}
+
+/**
+ * Enroll into a WSS previously discovered
+ *
+ * User provides WSSID of WSS, search for neighbor that has this WSS
+ * activated and attempt to enroll.
+ *
+ * &wss->mutex is held
+ */
+static
+int wlp_wss_enroll_discovered(struct wlp_wss *wss, struct wlp_uuid *wssid)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct wlp_neighbor_e *neighbor;
+ struct wlp_wssid_e *wssid_e;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ int result = -ENXIO;
+
+ wlp_wss_uuid_print(buf, sizeof(buf), wssid);
+ d_fnstart(5, dev, "wss %p, wssid %s \n", wss, buf);
+ mutex_lock(&wlp->nbmutex);
+ list_for_each_entry(neighbor, &wlp->neighbors, node) {
+ list_for_each_entry(wssid_e, &neighbor->wssid, node) {
+ if (!memcmp(wssid, &wssid_e->wssid, sizeof(*wssid))) {
+ d_printf(5, dev, "Found WSSID %s in neighbor "
+ "%02x:%02x cache. \n", buf,
+ neighbor->uwb_dev->dev_addr.data[1],
+ neighbor->uwb_dev->dev_addr.data[0]);
+ result = wlp_enroll_neighbor(wlp, neighbor,
+ wss, wssid);
+ if (result == 0) /* enrollment success */
+ goto out;
+ break;
+ }
+ }
+ }
+out:
+ if (result == -ENXIO)
+ dev_err(dev, "WLP: Cannot find WSSID %s in cache. \n", buf);
+ mutex_unlock(&wlp->nbmutex);
+ d_fnend(5, dev, "wss %p, wssid %s, result %d \n", wss, buf, result);
+ return result;
+}
+
+/**
+ * Enroll into WSS with provided WSSID, registrar may be provided
+ *
+ * @wss: out WSS that will be enrolled
+ * @wssid: wssid of neighboring WSS that we want to enroll in
+ * @devaddr: registrar can be specified, will be broadcast (ff:ff) if any
+ * neighbor can be used as registrar.
+ *
+ * &wss->mutex is held
+ */
+static
+int wlp_wss_enroll(struct wlp_wss *wss, struct wlp_uuid *wssid,
+ struct uwb_dev_addr *devaddr)
+{
+ int result;
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
+
+ wlp_wss_uuid_print(buf, sizeof(buf), wssid);
+ if (wss->state != WLP_WSS_STATE_NONE) {
+ dev_err(dev, "WLP: Already enrolled in WSS %s.\n", buf);
+ result = -EEXIST;
+ goto error;
+ }
+ if (!memcmp(&bcast, devaddr, sizeof(bcast))) {
+ d_printf(5, dev, "Request to enroll in discovered WSS "
+ "with WSSID %s \n", buf);
+ result = wlp_wss_enroll_discovered(wss, wssid);
+ } else {
+ d_printf(5, dev, "Request to enroll in WSSID %s with "
+ "registrar %02x:%02x\n", buf, devaddr->data[1],
+ devaddr->data[0]);
+ result = wlp_wss_enroll_target(wss, wssid, devaddr);
+ }
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to enroll into WSS %s, result %d \n",
+ buf, result);
+ goto error;
+ }
+ d_printf(2, dev, "Successfully enrolled into WSS %s \n", buf);
+ result = wlp_wss_sysfs_add(wss, buf);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to set up sysfs for WSS kobject.\n");
+ wlp_wss_reset(wss);
+ }
+error:
+ return result;
+
+}
+
+/**
+ * Activate given WSS
+ *
+ * Prior to activation a WSS must be enrolled. To activate a WSS a device
+ * includes the WSS hash in the WLP IE in its beacon in each superframe.
+ * WLP 0.99 [7.2.5].
+ *
+ * The WSS tag is also computed at this time. We only support one activated
+ * WSS so we can use the hash as a tag - there will never be a conflict.
+ *
+ * We currently only support one activated WSS so only one WSS hash is
+ * included in the WLP IE.
+ */
+static
+int wlp_wss_activate(struct wlp_wss *wss)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct uwb_rc *uwb_rc = wlp->rc;
+ int result;
+ struct {
+ struct wlp_ie wlp_ie;
+ u8 hash; /* only include one hash */
+ } ie_data;
+
+ d_fnstart(5, dev, "Activating WSS %p. \n", wss);
+ BUG_ON(wss->state != WLP_WSS_STATE_ENROLLED);
+ wss->hash = wlp_wss_comp_wssid_hash(&wss->wssid);
+ wss->tag = wss->hash;
+ memset(&ie_data, 0, sizeof(ie_data));
+ ie_data.wlp_ie.hdr.element_id = UWB_IE_WLP;
+ ie_data.wlp_ie.hdr.length = sizeof(ie_data) - sizeof(struct uwb_ie_hdr);
+ wlp_ie_set_hash_length(&ie_data.wlp_ie, sizeof(ie_data.hash));
+ ie_data.hash = wss->hash;
+ result = uwb_rc_ie_add(uwb_rc, &ie_data.wlp_ie.hdr,
+ sizeof(ie_data));
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to add WLP IE to beacon. "
+ "result = %d.\n", result);
+ goto error_wlp_ie;
+ }
+ wss->state = WLP_WSS_STATE_ACTIVE;
+ result = 0;
+error_wlp_ie:
+ d_fnend(5, dev, "Activating WSS %p, result = %d \n", wss, result);
+ return result;
+}
+
+/**
+ * Enroll in and activate WSS identified by provided WSSID
+ *
+ * The neighborhood cache should contain a list of all neighbors and the
+ * WSS they have activated. Based on that cache we search which neighbor we
+ * can perform the association process with. The user also has option to
+ * specify which neighbor it prefers as registrar.
+ * Successful enrollment is followed by activation.
+ * Successful activation will create the sysfs directory containing
+ * specific information regarding this WSS.
+ */
+int wlp_wss_enroll_activate(struct wlp_wss *wss, struct wlp_uuid *wssid,
+ struct uwb_dev_addr *devaddr)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = 0;
+ char buf[WLP_WSS_UUID_STRSIZE];
+
+ d_fnstart(5, dev, "Enrollment and activation requested. \n");
+ mutex_lock(&wss->mutex);
+ result = wlp_wss_enroll(wss, wssid, devaddr);
+ if (result < 0) {
+ wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
+ dev_err(dev, "WLP: Enrollment into WSS %s failed.\n", buf);
+ goto error_enroll;
+ }
+ result = wlp_wss_activate(wss);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to activate WSS. Undoing enrollment "
+ "result = %d \n", result);
+ /* Undo enrollment */
+ wlp_wss_reset(wss);
+ goto error_activate;
+ }
+error_activate:
+error_enroll:
+ mutex_unlock(&wss->mutex);
+ d_fnend(5, dev, "Completed. result = %d \n", result);
+ return result;
+}
+
+/**
+ * Create, enroll, and activate a new WSS
+ *
+ * @wssid: new wssid provided by user
+ * @name: WSS name requested by used.
+ * @sec_status: security status requested by user
+ *
+ * A user requested the creation of a new WSS. All operations are done
+ * locally. The new WSS will be stored locally, the hash will be included
+ * in the WLP IE, and the sysfs infrastructure for this WSS will be
+ * created.
+ */
+int wlp_wss_create_activate(struct wlp_wss *wss, struct wlp_uuid *wssid,
+ char *name, unsigned sec_status, unsigned accept)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = 0;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ d_fnstart(5, dev, "Request to create new WSS.\n");
+ result = wlp_wss_uuid_print(buf, sizeof(buf), wssid);
+ d_printf(5, dev, "Request to create WSS: WSSID=%s, name=%s, "
+ "sec_status=%u, accepting enrollment=%u \n",
+ buf, name, sec_status, accept);
+ if (!mutex_trylock(&wss->mutex)) {
+ dev_err(dev, "WLP: WLP association session in progress.\n");
+ return -EBUSY;
+ }
+ if (wss->state != WLP_WSS_STATE_NONE) {
+ dev_err(dev, "WLP: WSS already exists. Not creating new.\n");
+ result = -EEXIST;
+ goto out;
+ }
+ if (wss->kobj.parent == NULL) {
+ dev_err(dev, "WLP: WSS parent not ready. Is network interface "
+ "up?\n");
+ result = -ENXIO;
+ goto out;
+ }
+ if (sec_status == WLP_WSS_SECURE) {
+ dev_err(dev, "WLP: FIXME Creation of secure WSS not "
+ "supported yet.\n");
+ result = -EINVAL;
+ goto out;
+ }
+ wss->wssid = *wssid;
+ memcpy(wss->name, name, sizeof(wss->name));
+ wss->bcast = wlp_wss_sel_bcast_addr(wss);
+ wss->secure_status = sec_status;
+ wss->accept_enroll = accept;
+ /*wss->virtual_addr is initialized in call to wlp_wss_setup*/
+ /* sysfs infrastructure */
+ result = wlp_wss_sysfs_add(wss, buf);
+ if (result < 0) {
+ dev_err(dev, "Cannot set up sysfs for WSS kobject.\n");
+ wlp_wss_reset(wss);
+ goto out;
+ } else
+ result = 0;
+ wss->state = WLP_WSS_STATE_ENROLLED;
+ result = wlp_wss_activate(wss);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to activate WSS. Undoing "
+ "enrollment\n");
+ wlp_wss_reset(wss);
+ goto out;
+ }
+ result = 0;
+out:
+ mutex_unlock(&wss->mutex);
+ d_fnend(5, dev, "Completed. result = %d \n", result);
+ return result;
+}
+
+/**
+ * Determine if neighbor has WSS activated
+ *
+ * @returns: 1 if neighbor has WSS activated, zero otherwise
+ *
+ * This can be done in two ways:
+ * - send a C1 frame, parse C2/F0 response
+ * - examine the WLP IE sent by the neighbor
+ *
+ * The WLP IE is not fully supported in hardware so we use the C1/C2 frame
+ * exchange to determine if a WSS is activated. Using the WLP IE should be
+ * faster and should be used when it becomes possible.
+ */
+int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss,
+ struct uwb_dev_addr *dev_addr)
+{
+ int result = 0;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ DECLARE_COMPLETION_ONSTACK(completion);
+ struct wlp_session session;
+ struct sk_buff *skb;
+ struct wlp_frame_assoc *resp;
+ struct wlp_uuid wssid;
+
+ wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
+ d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
+ wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
+ mutex_lock(&wlp->mutex);
+ /* Send C1 association frame */
+ result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C1);
+ if (result < 0) {
+ dev_err(dev, "Unable to send C1 frame to neighbor "
+ "%02x:%02x (%d)\n", dev_addr->data[1],
+ dev_addr->data[0], result);
+ result = 0;
+ goto out;
+ }
+ /* Create session, wait for response */
+ session.exp_message = WLP_ASSOC_C2;
+ session.cb = wlp_session_cb;
+ session.cb_priv = &completion;
+ session.neighbor_addr = *dev_addr;
+ BUG_ON(wlp->session != NULL);
+ wlp->session = &session;
+ /* Wait for C2/F0 frame */
+ result = wait_for_completion_interruptible_timeout(&completion,
+ WLP_PER_MSG_TIMEOUT * HZ);
+ if (result == 0) {
+ dev_err(dev, "Timeout while sending C1 to neighbor "
+ "%02x:%02x.\n", dev_addr->data[1],
+ dev_addr->data[0]);
+ goto out;
+ }
+ if (result < 0) {
+ dev_err(dev, "Unable to send C1 to neighbor %02x:%02x.\n",
+ dev_addr->data[1], dev_addr->data[0]);
+ result = 0;
+ goto out;
+ }
+ /* Parse message in session->data: it will be either C2 or F0 */
+ skb = session.data;
+ resp = (void *) skb->data;
+ d_printf(5, dev, "Received response to C1 frame. \n");
+ d_dump(5, dev, skb->data, skb->len > 72 ? 72 : skb->len);
+ if (resp->type == WLP_ASSOC_F0) {
+ result = wlp_parse_f0(wlp, skb);
+ if (result < 0)
+ dev_err(dev, "WLP: unable to parse incoming F0 "
+ "frame from neighbor %02x:%02x.\n",
+ dev_addr->data[1], dev_addr->data[0]);
+ result = 0;
+ goto error_resp_parse;
+ }
+ /* WLP version and message type fields have already been parsed */
+ result = wlp_get_wssid(wlp, (void *)resp + sizeof(*resp), &wssid,
+ skb->len - sizeof(*resp));
+ if (result < 0) {
+ dev_err(dev, "WLP: unable to obtain WSSID from C2 frame.\n");
+ result = 0;
+ goto error_resp_parse;
+ }
+ if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))) {
+ d_printf(5, dev, "WSSID in C2 frame matches local "
+ "active WSS.\n");
+ result = 1;
+ } else {
+ dev_err(dev, "WLP: Received a C2 frame without matching "
+ "WSSID.\n");
+ result = 0;
+ }
+error_resp_parse:
+ kfree_skb(skb);
+out:
+ wlp->session = NULL;
+ mutex_unlock(&wlp->mutex);
+ d_fnend(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
+ wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
+ return result;
+}
+
+/**
+ * Activate connection with neighbor by updating EDA cache
+ *
+ * @wss: local WSS to which neighbor wants to connect
+ * @dev_addr: neighbor's address
+ * @wssid: neighbor's WSSID - must be same as our WSS's WSSID
+ * @tag: neighbor's WSS tag used to identify frames transmitted by it
+ * @virt_addr: neighbor's virtual EUI-48
+ */
+static
+int wlp_wss_activate_connection(struct wlp *wlp, struct wlp_wss *wss,
+ struct uwb_dev_addr *dev_addr,
+ struct wlp_uuid *wssid, u8 *tag,
+ struct uwb_mac_addr *virt_addr)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = 0;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ wlp_wss_uuid_print(buf, sizeof(buf), wssid);
+ d_fnstart(5, dev, "wlp %p, wss %p, wssid %s, tag %u, virtual "
+ "%02x:%02x:%02x:%02x:%02x:%02x \n", wlp, wss, buf, *tag,
+ virt_addr->data[0], virt_addr->data[1], virt_addr->data[2],
+ virt_addr->data[3], virt_addr->data[4], virt_addr->data[5]);
+
+ if (!memcmp(wssid, &wss->wssid, sizeof(*wssid))) {
+ d_printf(5, dev, "WSSID from neighbor frame matches local "
+ "active WSS.\n");
+ /* Update EDA cache */
+ result = wlp_eda_update_node(&wlp->eda, dev_addr, wss,
+ (void *) virt_addr->data, *tag,
+ WLP_WSS_CONNECTED);
+ if (result < 0)
+ dev_err(dev, "WLP: Unable to update EDA cache "
+ "with new connected neighbor information.\n");
+ } else {
+ dev_err(dev, "WLP: Neighbor does not have matching "
+ "WSSID.\n");
+ result = -EINVAL;
+ }
+
+ d_fnend(5, dev, "wlp %p, wss %p, wssid %s, tag %u, virtual "
+ "%02x:%02x:%02x:%02x:%02x:%02x, result = %d \n",
+ wlp, wss, buf, *tag,
+ virt_addr->data[0], virt_addr->data[1], virt_addr->data[2],
+ virt_addr->data[3], virt_addr->data[4], virt_addr->data[5],
+ result);
+
+ return result;
+}
+
+/**
+ * Connect to WSS neighbor
+ *
+ * Use C3/C4 exchange to determine if neighbor has WSS activated and
+ * retrieve the WSS tag and virtual EUI-48 of the neighbor.
+ */
+static
+int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss,
+ struct uwb_dev_addr *dev_addr)
+{
+ int result;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ char buf[WLP_WSS_UUID_STRSIZE];
+ struct wlp_uuid wssid;
+ u8 tag;
+ struct uwb_mac_addr virt_addr;
+ DECLARE_COMPLETION_ONSTACK(completion);
+ struct wlp_session session;
+ struct wlp_frame_assoc *resp;
+ struct sk_buff *skb;
+
+ wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
+ d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
+ wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
+ mutex_lock(&wlp->mutex);
+ /* Send C3 association frame */
+ result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C3);
+ if (result < 0) {
+ dev_err(dev, "Unable to send C3 frame to neighbor "
+ "%02x:%02x (%d)\n", dev_addr->data[1],
+ dev_addr->data[0], result);
+ goto out;
+ }
+ /* Create session, wait for response */
+ session.exp_message = WLP_ASSOC_C4;
+ session.cb = wlp_session_cb;
+ session.cb_priv = &completion;
+ session.neighbor_addr = *dev_addr;
+ BUG_ON(wlp->session != NULL);
+ wlp->session = &session;
+ /* Wait for C4/F0 frame */
+ result = wait_for_completion_interruptible_timeout(&completion,
+ WLP_PER_MSG_TIMEOUT * HZ);
+ if (result == 0) {
+ dev_err(dev, "Timeout while sending C3 to neighbor "
+ "%02x:%02x.\n", dev_addr->data[1],
+ dev_addr->data[0]);
+ result = -ETIMEDOUT;
+ goto out;
+ }
+ if (result < 0) {
+ dev_err(dev, "Unable to send C3 to neighbor %02x:%02x.\n",
+ dev_addr->data[1], dev_addr->data[0]);
+ goto out;
+ }
+ /* Parse message in session->data: it will be either C4 or F0 */
+ skb = session.data;
+ resp = (void *) skb->data;
+ d_printf(5, dev, "Received response to C3 frame. \n");
+ d_dump(5, dev, skb->data, skb->len > 72 ? 72 : skb->len);
+ if (resp->type == WLP_ASSOC_F0) {
+ result = wlp_parse_f0(wlp, skb);
+ if (result < 0)
+ dev_err(dev, "WLP: unable to parse incoming F0 "
+ "frame from neighbor %02x:%02x.\n",
+ dev_addr->data[1], dev_addr->data[0]);
+ result = -EINVAL;
+ goto error_resp_parse;
+ }
+ result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to parse C4 frame from neighbor.\n");
+ goto error_resp_parse;
+ }
+ result = wlp_wss_activate_connection(wlp, wss, dev_addr, &wssid, &tag,
+ &virt_addr);
+ if (result < 0) {
+ dev_err(dev, "WLP: Unable to activate connection to "
+ "neighbor %02x:%02x.\n", dev_addr->data[1],
+ dev_addr->data[0]);
+ goto error_resp_parse;
+ }
+error_resp_parse:
+ kfree_skb(skb);
+out:
+ /* Record that we unsuccessfully tried to connect to this neighbor */
+ if (result < 0)
+ wlp_eda_update_node_state(&wlp->eda, dev_addr,
+ WLP_WSS_CONNECT_FAILED);
+ wlp->session = NULL;
+ mutex_unlock(&wlp->mutex);
+ d_fnend(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
+ wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
+ return result;
+}
+
+/**
+ * Connect to neighbor with common WSS, send pending frame
+ *
+ * This function is scheduled when a frame is destined to a neighbor with
+ * which we do not have a connection. A copy of the EDA cache entry is
+ * provided - not the actual cache entry (because it is protected by a
+ * spinlock).
+ *
+ * First determine if neighbor has the same WSS activated, connect if it
+ * does. The C3/C4 exchange is dual purpose to determine if neighbor has
+ * WSS activated and proceed with the connection.
+ *
+ * The frame that triggered the connection setup is sent after connection
+ * setup.
+ *
+ * network queue is stopped - we need to restart when done
+ *
+ */
+static
+void wlp_wss_connect_send(struct work_struct *ws)
+{
+ struct wlp_assoc_conn_ctx *conn_ctx = container_of(ws,
+ struct wlp_assoc_conn_ctx,
+ ws);
+ struct wlp *wlp = conn_ctx->wlp;
+ struct sk_buff *skb = conn_ctx->skb;
+ struct wlp_eda_node *eda_entry = &conn_ctx->eda_entry;
+ struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
+ struct wlp_wss *wss = &wlp->wss;
+ int result;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ char buf[WLP_WSS_UUID_STRSIZE];
+
+ mutex_lock(&wss->mutex);
+ wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
+ d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
+ wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
+ if (wss->state < WLP_WSS_STATE_ACTIVE) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Attempting to connect with "
+ "WSS that is not active or connected.\n");
+ dev_kfree_skb(skb);
+ goto out;
+ }
+ /* Establish connection - send C3 rcv C4 */
+ result = wlp_wss_connect_neighbor(wlp, wss, dev_addr);
+ if (result < 0) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Unable to establish connection "
+ "with neighbor %02x:%02x.\n",
+ dev_addr->data[1], dev_addr->data[0]);
+ dev_kfree_skb(skb);
+ goto out;
+ }
+ /* EDA entry changed, update the local copy being used */
+ result = wlp_copy_eda_node(&wlp->eda, dev_addr, eda_entry);
+ if (result < 0) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Cannot find EDA entry for "
+ "neighbor %02x:%02x \n",
+ dev_addr->data[1], dev_addr->data[0]);
+ }
+ result = wlp_wss_prep_hdr(wlp, eda_entry, skb);
+ if (result < 0) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Unable to prepare frame header for "
+ "transmission (neighbor %02x:%02x). \n",
+ dev_addr->data[1], dev_addr->data[0]);
+ dev_kfree_skb(skb);
+ goto out;
+ }
+ BUG_ON(wlp->xmit_frame == NULL);
+ result = wlp->xmit_frame(wlp, skb, dev_addr);
+ if (result < 0) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Unable to transmit frame: %d\n",
+ result);
+ if (result == -ENXIO)
+ dev_err(dev, "WLP: Is network interface up? \n");
+ /* We could try again ... */
+ dev_kfree_skb(skb);/*we need to free if tx fails */
+ }
+out:
+ kfree(conn_ctx);
+ BUG_ON(wlp->start_queue == NULL);
+ wlp->start_queue(wlp);
+ mutex_unlock(&wss->mutex);
+ d_fnend(5, dev, "wlp %p, wss %p (wssid %s)\n", wlp, wss, buf);
+}
+
+/**
+ * Add WLP header to outgoing skb
+ *
+ * @eda_entry: pointer to neighbor's entry in the EDA cache
+ * @_skb: skb containing data destined to the neighbor
+ */
+int wlp_wss_prep_hdr(struct wlp *wlp, struct wlp_eda_node *eda_entry,
+ void *_skb)
+{
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = 0;
+ unsigned char *eth_addr = eda_entry->eth_addr;
+ struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
+ struct sk_buff *skb = _skb;
+ struct wlp_frame_std_abbrv_hdr *std_hdr;
+
+ d_fnstart(6, dev, "wlp %p \n", wlp);
+ if (eda_entry->state == WLP_WSS_CONNECTED) {
+ /* Add WLP header */
+ BUG_ON(skb_headroom(skb) < sizeof(*std_hdr));
+ std_hdr = (void *) __skb_push(skb, sizeof(*std_hdr));
+ std_hdr->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
+ std_hdr->hdr.type = WLP_FRAME_STANDARD;
+ std_hdr->tag = eda_entry->wss->tag;
+ } else {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Destination neighbor (Ethernet: "
+ "%02x:%02x:%02x:%02x:%02x:%02x, Dev: "
+ "%02x:%02x) is not connected. \n", eth_addr[0],
+ eth_addr[1], eth_addr[2], eth_addr[3],
+ eth_addr[4], eth_addr[5], dev_addr->data[1],
+ dev_addr->data[0]);
+ result = -EINVAL;
+ }
+ d_fnend(6, dev, "wlp %p \n", wlp);
+ return result;
+}
+
+
+/**
+ * Prepare skb for neighbor: connect if not already and prep WLP header
+ *
+ * This function is called in interrupt context, but it needs to sleep. We
+ * temporarily stop the net queue to establish the WLP connection.
+ * Setup of the WLP connection and restart of queue is scheduled
+ * on the default work queue.
+ *
+ * run with eda->lock held (spinlock)
+ */
+int wlp_wss_connect_prep(struct wlp *wlp, struct wlp_eda_node *eda_entry,
+ void *_skb)
+{
+ int result = 0;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
+ unsigned char *eth_addr = eda_entry->eth_addr;
+ struct sk_buff *skb = _skb;
+ struct wlp_assoc_conn_ctx *conn_ctx;
+
+ d_fnstart(5, dev, "wlp %p\n", wlp);
+ d_printf(5, dev, "To neighbor %02x:%02x with eth "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n", dev_addr->data[1],
+ dev_addr->data[0], eth_addr[0], eth_addr[1], eth_addr[2],
+ eth_addr[3], eth_addr[4], eth_addr[5]);
+ if (eda_entry->state == WLP_WSS_UNCONNECTED) {
+ /* We don't want any more packets while we set up connection */
+ BUG_ON(wlp->stop_queue == NULL);
+ wlp->stop_queue(wlp);
+ conn_ctx = kmalloc(sizeof(*conn_ctx), GFP_ATOMIC);
+ if (conn_ctx == NULL) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Unable to allocate memory "
+ "for connection handling.\n");
+ result = -ENOMEM;
+ goto out;
+ }
+ conn_ctx->wlp = wlp;
+ conn_ctx->skb = skb;
+ conn_ctx->eda_entry = *eda_entry;
+ INIT_WORK(&conn_ctx->ws, wlp_wss_connect_send);
+ schedule_work(&conn_ctx->ws);
+ result = 1;
+ } else if (eda_entry->state == WLP_WSS_CONNECT_FAILED) {
+ /* Previous connection attempts failed, don't retry - see
+ * conditions for connection in WLP 0.99 [7.6.2] */
+ if (printk_ratelimit())
+ dev_err(dev, "Could not connect to neighbor "
+ "previously. Not retrying. \n");
+ result = -ENONET;
+ goto out;
+ } else { /* eda_entry->state == WLP_WSS_CONNECTED */
+ d_printf(5, dev, "Neighbor is connected, preparing frame.\n");
+ result = wlp_wss_prep_hdr(wlp, eda_entry, skb);
+ }
+out:
+ d_fnend(5, dev, "wlp %p, result = %d \n", wlp, result);
+ return result;
+}
+
+/**
+ * Emulate broadcast: copy skb, send copy to neighbor (connect if not already)
+ *
+ * We need to copy skbs in the case where we emulate broadcast through
+ * unicast. We copy instead of clone because we are modifying the data of
+ * the frame after copying ... clones share data so we cannot emulate
+ * broadcast using clones.
+ *
+ * run with eda->lock held (spinlock)
+ */
+int wlp_wss_send_copy(struct wlp *wlp, struct wlp_eda_node *eda_entry,
+ void *_skb)
+{
+ int result = -ENOMEM;
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ struct sk_buff *skb = _skb;
+ struct sk_buff *copy;
+ struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
+
+ d_fnstart(5, dev, "to neighbor %02x:%02x, skb (%p) \n",
+ dev_addr->data[1], dev_addr->data[0], skb);
+ copy = skb_copy(skb, GFP_ATOMIC);
+ if (copy == NULL) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Unable to copy skb for "
+ "transmission.\n");
+ goto out;
+ }
+ result = wlp_wss_connect_prep(wlp, eda_entry, copy);
+ if (result < 0) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Unable to connect/send skb "
+ "to neighbor.\n");
+ dev_kfree_skb_irq(copy);
+ goto out;
+ } else if (result == 1)
+ /* Frame will be transmitted separately */
+ goto out;
+ BUG_ON(wlp->xmit_frame == NULL);
+ result = wlp->xmit_frame(wlp, copy, dev_addr);
+ if (result < 0) {
+ if (printk_ratelimit())
+ dev_err(dev, "WLP: Unable to transmit frame: %d\n",
+ result);
+ if ((result == -ENXIO) && printk_ratelimit())
+ dev_err(dev, "WLP: Is network interface up? \n");
+ /* We could try again ... */
+ dev_kfree_skb_irq(copy);/*we need to free if tx fails */
+ }
+out:
+ d_fnend(5, dev, "to neighbor %02x:%02x \n", dev_addr->data[1],
+ dev_addr->data[0]);
+ return result;
+}
+
+
+/**
+ * Setup WSS
+ *
+ * Should be called by network driver after the interface has been given a
+ * MAC address.
+ */
+int wlp_wss_setup(struct net_device *net_dev, struct wlp_wss *wss)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ int result = 0;
+ d_fnstart(5, dev, "wss (%p) \n", wss);
+ mutex_lock(&wss->mutex);
+ wss->kobj.parent = &net_dev->dev.kobj;
+ if (!is_valid_ether_addr(net_dev->dev_addr)) {
+ dev_err(dev, "WLP: Invalid MAC address. Cannot use for"
+ "virtual.\n");
+ result = -EINVAL;
+ goto out;
+ }
+ memcpy(wss->virtual_addr.data, net_dev->dev_addr,
+ sizeof(wss->virtual_addr.data));
+out:
+ mutex_unlock(&wss->mutex);
+ d_fnend(5, dev, "wss (%p) \n", wss);
+ return result;
+}
+EXPORT_SYMBOL_GPL(wlp_wss_setup);
+
+/**
+ * Remove WSS
+ *
+ * Called by client that configured WSS through wlp_wss_setup(). This
+ * function is called when client no longer needs WSS, eg. client shuts
+ * down.
+ *
+ * We remove the WLP IE from the beacon before initiating local cleanup.
+ */
+void wlp_wss_remove(struct wlp_wss *wss)
+{
+ struct wlp *wlp = container_of(wss, struct wlp, wss);
+ struct device *dev = &wlp->rc->uwb_dev.dev;
+ d_fnstart(5, dev, "wss (%p) \n", wss);
+ mutex_lock(&wss->mutex);
+ if (wss->state == WLP_WSS_STATE_ACTIVE)
+ uwb_rc_ie_rm(wlp->rc, UWB_IE_WLP);
+ if (wss->state != WLP_WSS_STATE_NONE) {
+ sysfs_remove_group(&wss->kobj, &wss_attr_group);
+ kobject_put(&wss->kobj);
+ }
+ wss->kobj.parent = NULL;
+ memset(&wss->virtual_addr, 0, sizeof(wss->virtual_addr));
+ /* Cleanup EDA cache */
+ wlp_eda_release(&wlp->eda);
+ wlp_eda_init(&wlp->eda);
+ mutex_unlock(&wss->mutex);
+ d_fnend(5, dev, "wss (%p) \n", wss);
+}
+EXPORT_SYMBOL_GPL(wlp_wss_remove);
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 6fa0b9d5559..d4cfed0b26d 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -19,7 +19,7 @@
#include <linux/backlight.h>
#include <cpu/dac.h>
-#include <asm/hp6xx.h>
+#include <mach/hp6xx.h>
#include <asm/hd64461.h>
#define HP680_MAX_INTENSITY 255
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 217c5118ae9..cd5f20da738 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1002,101 +1002,132 @@ fb_blank(struct fb_info *info, int blank)
return ret;
}
-static int
-fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+static long
+fb_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
- struct fb_info *info = registered_fb[fbidx];
- struct fb_ops *fb = info->fbops;
+ struct fb_info *info;
+ struct fb_ops *fb;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
struct fb_con2fbmap con2fb;
struct fb_cmap_user cmap;
struct fb_event event;
void __user *argp = (void __user *)arg;
- int i;
-
- if (!fb)
+ long ret = 0;
+
+ info = registered_fb[fbidx];
+ mutex_lock(&info->lock);
+ fb = info->fbops;
+
+ if (!fb) {
+ mutex_unlock(&info->lock);
return -ENODEV;
+ }
switch (cmd) {
case FBIOGET_VSCREENINFO:
- return copy_to_user(argp, &info->var,
+ ret = copy_to_user(argp, &info->var,
sizeof(var)) ? -EFAULT : 0;
+ break;
case FBIOPUT_VSCREENINFO:
- if (copy_from_user(&var, argp, sizeof(var)))
- return -EFAULT;
+ if (copy_from_user(&var, argp, sizeof(var))) {
+ ret = -EFAULT;
+ break;
+ }
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
- i = fb_set_var(info, &var);
+ ret = fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem();
- if (i) return i;
- if (copy_to_user(argp, &var, sizeof(var)))
- return -EFAULT;
- return 0;
+ if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
+ ret = -EFAULT;
+ break;
case FBIOGET_FSCREENINFO:
- return copy_to_user(argp, &info->fix,
+ ret = copy_to_user(argp, &info->fix,
sizeof(fix)) ? -EFAULT : 0;
+ break;
case FBIOPUTCMAP:
if (copy_from_user(&cmap, argp, sizeof(cmap)))
- return -EFAULT;
- return (fb_set_user_cmap(&cmap, info));
+ ret = -EFAULT;
+ else
+ ret = fb_set_user_cmap(&cmap, info);
+ break;
case FBIOGETCMAP:
if (copy_from_user(&cmap, argp, sizeof(cmap)))
- return -EFAULT;
- return fb_cmap_to_user(&info->cmap, &cmap);
+ ret = -EFAULT;
+ else
+ ret = fb_cmap_to_user(&info->cmap, &cmap);
+ break;
case FBIOPAN_DISPLAY:
- if (copy_from_user(&var, argp, sizeof(var)))
- return -EFAULT;
+ if (copy_from_user(&var, argp, sizeof(var))) {
+ ret = -EFAULT;
+ break;
+ }
acquire_console_sem();
- i = fb_pan_display(info, &var);
+ ret = fb_pan_display(info, &var);
release_console_sem();
- if (i)
- return i;
- if (copy_to_user(argp, &var, sizeof(var)))
- return -EFAULT;
- return 0;
+ if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
+ ret = -EFAULT;
+ break;
case FBIO_CURSOR:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
case FBIOGET_CON2FBMAP:
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
- return -EFAULT;
- if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
- return -EINVAL;
- con2fb.framebuffer = -1;
- event.info = info;
- event.data = &con2fb;
- fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
- return copy_to_user(argp, &con2fb,
+ ret = -EFAULT;
+ else if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
+ ret = -EINVAL;
+ else {
+ con2fb.framebuffer = -1;
+ event.info = info;
+ event.data = &con2fb;
+ fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP,
+ &event);
+ ret = copy_to_user(argp, &con2fb,
sizeof(con2fb)) ? -EFAULT : 0;
+ }
+ break;
case FBIOPUT_CON2FBMAP:
- if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
- return - EFAULT;
- if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
- return -EINVAL;
- if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
- return -EINVAL;
- if (!registered_fb[con2fb.framebuffer])
- request_module("fb%d", con2fb.framebuffer);
+ if (copy_from_user(&con2fb, argp, sizeof(con2fb))) {
+ ret = -EFAULT;
+ break;
+ }
+ if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) {
+ ret = -EINVAL;
+ break;
+ }
+ if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) {
+ ret = -EINVAL;
+ break;
+ }
if (!registered_fb[con2fb.framebuffer])
- return -EINVAL;
+ request_module("fb%d", con2fb.framebuffer);
+ if (!registered_fb[con2fb.framebuffer]) {
+ ret = -EINVAL;
+ break;
+ }
event.info = info;
event.data = &con2fb;
- return fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP,
+ ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP,
&event);
+ break;
case FBIOBLANK:
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
- i = fb_blank(info, arg);
+ ret = fb_blank(info, arg);
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem();
- return i;
+ break;;
default:
if (fb->fb_ioctl == NULL)
- return -EINVAL;
- return fb->fb_ioctl(info, cmd, arg);
+ ret = -ENOTTY;
+ else
+ ret = fb->fb_ioctl(info, cmd, arg);
}
+ mutex_unlock(&info->lock);
+ return ret;
}
#ifdef CONFIG_COMPAT
@@ -1150,7 +1181,7 @@ static int fb_getput_cmap(struct inode *inode, struct file *file,
put_user(compat_ptr(data), &cmap->transp))
return -EFAULT;
- err = fb_ioctl(inode, file, cmd, (unsigned long) cmap);
+ err = fb_ioctl(file, cmd, (unsigned long) cmap);
if (!err) {
if (copy_in_user(&cmap32->start,
@@ -1204,7 +1235,7 @@ static int fb_get_fscreeninfo(struct inode *inode, struct file *file,
old_fs = get_fs();
set_fs(KERNEL_DS);
- err = fb_ioctl(inode, file, cmd, (unsigned long) &fix);
+ err = fb_ioctl(file, cmd, (unsigned long) &fix);
set_fs(old_fs);
if (!err)
@@ -1222,7 +1253,7 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct fb_ops *fb = info->fbops;
long ret = -ENOIOCTLCMD;
- lock_kernel();
+ mutex_lock(&info->lock);
switch(cmd) {
case FBIOGET_VSCREENINFO:
case FBIOPUT_VSCREENINFO:
@@ -1231,7 +1262,7 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case FBIOPUT_CON2FBMAP:
arg = (unsigned long) compat_ptr(arg);
case FBIOBLANK:
- ret = fb_ioctl(inode, file, cmd, arg);
+ ret = fb_ioctl(file, cmd, arg);
break;
case FBIOGET_FSCREENINFO:
@@ -1248,7 +1279,7 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = fb->fb_compat_ioctl(info, cmd, arg);
break;
}
- unlock_kernel();
+ mutex_unlock(&info->lock);
return ret;
}
#endif
@@ -1270,13 +1301,13 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
return -ENODEV;
if (fb->fb_mmap) {
int res;
- lock_kernel();
+ mutex_lock(&info->lock);
res = fb->fb_mmap(info, vma);
- unlock_kernel();
+ mutex_unlock(&info->lock);
return res;
}
- lock_kernel();
+ mutex_lock(&info->lock);
/* frame buffer memory */
start = info->fix.smem_start;
@@ -1285,13 +1316,13 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
/* memory mapped io */
off -= len;
if (info->var.accel_flags) {
- unlock_kernel();
+ mutex_unlock(&info->lock);
return -EINVAL;
}
start = info->fix.mmio_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
}
- unlock_kernel();
+ mutex_unlock(&info->lock);
start &= PAGE_MASK;
if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL;
@@ -1315,13 +1346,13 @@ fb_open(struct inode *inode, struct file *file)
if (fbidx >= FB_MAX)
return -ENODEV;
- lock_kernel();
- if (!(info = registered_fb[fbidx]))
+ info = registered_fb[fbidx];
+ if (!info)
request_module("fb%d", fbidx);
- if (!(info = registered_fb[fbidx])) {
- res = -ENODEV;
- goto out;
- }
+ info = registered_fb[fbidx];
+ if (!info)
+ return -ENODEV;
+ mutex_lock(&info->lock);
if (!try_module_get(info->fbops->owner)) {
res = -ENODEV;
goto out;
@@ -1337,7 +1368,7 @@ fb_open(struct inode *inode, struct file *file)
fb_deferred_io_open(info, inode, file);
#endif
out:
- unlock_kernel();
+ mutex_unlock(&info->lock);
return res;
}
@@ -1346,11 +1377,11 @@ fb_release(struct inode *inode, struct file *file)
{
struct fb_info * const info = file->private_data;
- lock_kernel();
+ mutex_lock(&info->lock);
if (info->fbops->fb_release)
info->fbops->fb_release(info,1);
module_put(info->fbops->owner);
- unlock_kernel();
+ mutex_unlock(&info->lock);
return 0;
}
@@ -1358,7 +1389,7 @@ static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
- .ioctl = fb_ioctl,
+ .unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif
@@ -1429,6 +1460,7 @@ register_framebuffer(struct fb_info *fb_info)
if (!registered_fb[i])
break;
fb_info->node = i;
+ mutex_init(&fb_info->lock);
fb_info->dev = device_create(fb_class, fb_info->device,
MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/drivers/video/imacfb.c
+++ /dev/null
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 4c32c06579a..efff672fd7b 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -16,7 +16,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <asm/sh_mobile_lcdc.h>
+#include <video/sh_mobile_lcdc.h>
#define PALETTE_NR 16
@@ -34,7 +34,9 @@ struct sh_mobile_lcdc_chan {
struct sh_mobile_lcdc_priv {
void __iomem *base;
+#ifdef CONFIG_HAVE_CLK
struct clk *clk;
+#endif
unsigned long lddckr;
struct sh_mobile_lcdc_chan ch[2];
};
@@ -260,6 +262,11 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
tmp = ch->ldmt1r_value;
tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28;
tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0;
lcdc_write_chan(ch, LDMT1R, tmp);
/* setup SYS bus */
@@ -422,6 +429,7 @@ static int sh_mobile_lcdc_setup_clocks(struct device *dev, int clock_source,
priv->lddckr = icksel << 16;
+#ifdef CONFIG_HAVE_CLK
if (str) {
priv->clk = clk_get(dev, str);
if (IS_ERR(priv->clk)) {
@@ -431,6 +439,7 @@ static int sh_mobile_lcdc_setup_clocks(struct device *dev, int clock_source,
clk_enable(priv->clk);
}
+#endif
return 0;
}
@@ -585,7 +594,6 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1;
}
- priv->lddckr = pdata->lddckr;
priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1);
for (i = 0; i < j; i++) {
@@ -688,10 +696,12 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
fb_dealloc_cmap(&info->cmap);
}
+#ifdef CONFIG_HAVE_CLK
if (priv->clk) {
clk_disable(priv->clk);
clk_put(priv->clk);
}
+#endif
if (priv->base)
iounmap(priv->base);
diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c
index ed6b0576208..1f09d4e4144 100644
--- a/drivers/w1/slaves/w1_ds2760.c
+++ b/drivers/w1/slaves/w1_ds2760.c
@@ -80,7 +80,6 @@ static struct bin_attribute w1_ds2760_bin_attr = {
.attr = {
.name = "w1_slave",
.mode = S_IRUGO,
- .owner = THIS_MODULE,
},
.size = DS2760_DATA_SIZE,
.read = w1_ds2760_read_bin,
diff --git a/drivers/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c
index 05a28106e8e..8782ec1f5aa 100644
--- a/drivers/watchdog/ib700wdt.c
+++ b/drivers/watchdog/ib700wdt.c
@@ -154,7 +154,7 @@ static int ibwdt_set_heartbeat(int t)
return -EINVAL;
for (i = 0x0F; i > -1; i--)
- if (wd_times[i] > t)
+ if (wd_times[i] >= t)
break;
wd_margin = i;
return 0;
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
index c73b5e2919c..ada8ad82d99 100644
--- a/drivers/watchdog/w83697ug_wdt.c
+++ b/drivers/watchdog/w83697ug_wdt.c
@@ -102,7 +102,7 @@ static void w83697ug_select_wd_register(void)
} else {
printk(KERN_ERR PFX "No W83697UG/UF could be found\n");
- return -EIO;
+ return;
}
outb_p(0x07, WDT_EFER); /* point to logical device number reg */
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
index 565280ec1c6..974f56d1ebe 100644
--- a/drivers/xen/cpu_hotplug.c
+++ b/drivers/xen/cpu_hotplug.c
@@ -2,7 +2,7 @@
#include <xen/xenbus.h>
-#include <asm-x86/xen/hypervisor.h>
+#include <asm/xen/hypervisor.h>
#include <asm/cpu.h>
static void enable_hotplug_cpu(int cpu)
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index c3290bc186a..9ce1ab6c268 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -125,7 +125,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
BUG_ON(irq == -1);
#ifdef CONFIG_SMP
- irq_desc[irq].affinity = cpumask_of_cpu(cpu);
+ irq_to_desc(irq)->affinity = cpumask_of_cpu(cpu);
#endif
__clear_bit(chn, cpu_evtchn_mask[cpu_evtchn[chn]]);
@@ -137,10 +137,12 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
static void init_evtchn_cpu_bindings(void)
{
#ifdef CONFIG_SMP
+ struct irq_desc *desc;
int i;
+
/* By default all event channels notify CPU#0. */
- for (i = 0; i < NR_IRQS; i++)
- irq_desc[i].affinity = cpumask_of_cpu(0);
+ for_each_irq_desc(i, desc)
+ desc->affinity = cpumask_of_cpu(0);
#endif
memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
@@ -229,12 +231,12 @@ static int find_unbound_irq(void)
int irq;
/* Only allocate from dynirq range */
- for (irq = 0; irq < NR_IRQS; irq++)
+ for_each_irq_nr(irq)
if (irq_bindcount[irq] == 0)
break;
- if (irq == NR_IRQS)
- panic("No available IRQ to bind to: increase NR_IRQS!\n");
+ if (irq == nr_irqs)
+ panic("No available IRQ to bind to: increase nr_irqs!\n");
return irq;
}
@@ -790,7 +792,7 @@ void xen_irq_resume(void)
mask_evtchn(evtchn);
/* No IRQ <-> event-channel mappings. */
- for (irq = 0; irq < NR_IRQS; irq++)
+ for_each_irq_nr(irq)
irq_info[irq].evtchn = 0; /* zap event-channel binding */
for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
@@ -822,7 +824,7 @@ void __init xen_init_IRQ(void)
mask_evtchn(i);
/* Dynamic IRQ space is currently unbound. Zero the refcnts. */
- for (i = 0; i < NR_IRQS; i++)
+ for_each_irq_nr(i)
irq_bindcount[i] = 0;
irq_ctx_init(smp_processor_id());